Clone in a terminal:
Commit 836c66f
Johan Mattsson - 2012-08-18T19:29:40+00:00
836c66f6a878682b971e0bd7ba5c2ba61fc1e559johan.mattsson.m@gmail.com

merge two paths

Changed files (6)

Diff

diff --git a/src/EditPointHandle.vala b/src/EditPointHandle.valaindex 6a482e7..8112ac8 100644--- a/src/EditPointHandle.vala+++ b/src/EditPointHandle.vala@@ -53,6 +53,16 @@ class EditPointHandle  { 		this.active = false; 	} +	public EditPointHandle copy () {+		EditPointHandle n = new EditPointHandle.empty ();+		n.angle = angle;+		n.length = length;+		n.parent = parent;+		n.type = type;+		n.active = active;+		return n;+	}+ 	public void set_point_type (PointType point_type) { 		type = point_type; 	}diff --git a/src/Glyph.vala b/src/Glyph.valaindex abb4c36..69d9620 100644--- a/src/Glyph.vala+++ b/src/Glyph.vala@@ -1663,8 +1663,15 @@ class Glyph : FontDisplay { 		 		delete_invisible_paths (); 		-		if (path_list.length () >= 2)-			((!)path_list.first ()).data.merge (((!)path_list.last ()).data);+		if (path_list.length () >= 2) {+			m = ((!) path_list.first ()).data.merge (((!) path_list.last ()).data);+			delete_path (path_list.first ().data);+			delete_path (path_list.last ().data);++			((!) m).close ();+			+			add_path (((!) m).copy ());+		} 	} } diff --git a/src/Intersection.vala b/src/Intersection.valanew file mode 100644index 0000000..c3e3533--- /dev/null+++ b/src/Intersection.vala@@ -0,0 +1,36 @@+/*+    Copyright (C) 2012 Johan Mattsson++    This program is free software: you can redistribute it and/or modify+    it under the terms of the GNU General Public License as published by+    the Free Software Foundation, either version 3 of the License, or+    (at your option) any later version.++    This program is distributed in the hope that it will be useful,+    but WITHOUT ANY WARRANTY; without even the implied warranty of+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+    GNU General Public License for more details.++    You should have received a copy of the GNU General Public License+    along with this program.  If not, see <http://www.gnu.org/licenses/>.+*/++using Math;++namespace Supplement {++class Intersection {+	public double x;+	public double y;+	public double distance;+	+	public EditPoint editpoint_a;+	public EditPoint editpoint_b;+	+	public Intersection (double x, double y, double distance) {+		this.x = x;+		this.y = y;+	}+}++}diff --git a/src/IntersectionList.vala b/src/IntersectionList.valanew file mode 100644index 0000000..9070455--- /dev/null+++ b/src/IntersectionList.vala@@ -0,0 +1,235 @@+/*+    Copyright (C) 2012 Johan Mattsson++    This program is free software: you can redistribute it and/or modify+    it under the terms of the GNU General Public License as published by+    the Free Software Foundation, either version 3 of the License, or+    (at your option) any later version.++    This program is distributed in the hope that it will be useful,+    but WITHOUT ANY WARRANTY; without even the implied warranty of+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+    GNU General Public License for more details.++    You should have received a copy of the GNU General Public License+    along with this program.  If not, see <http://www.gnu.org/licenses/>.+*/++using Math;++namespace Supplement {++class IntersectionList {+	public List<Intersection> points = new List<Intersection> ();+	+	public void add (Intersection i) {+		double d;+		Intersection l;+				+		if (points.length () == 0) {+			points.append (i);+			return;+		}+		+		if (has_point (i)) {+			return;+		}+	+		l = ((!) points.last ()).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 ());+			points.append (i);+			return;+		}++		if (d < 0.3) {+			return;+		}++		points.append (i);+	}+	+	public bool has_edit_point (EditPoint e) {+		foreach (Intersection n in points) {+			if (n.editpoint_a == e || n.editpoint_b == e) {+				return true;+			}+		}+		+		return false;+	}+	+	bool has_point (Intersection i) {+		foreach (Intersection n in points) {+			if (i.x == n.x && i.y == n.y) {+				return true;+			}+		}+		+		return false;+	}+	+	public int get_point_index (EditPoint e) {+		int i = 0;+		foreach (Intersection n in points) {+			if (e.x == n.x && e.y == n.y) {+				return i;+			}+			i++;+		}+		return -1;+	}+	+	public Intersection? get_next_intersection (EditPoint e) {+		bool found = false;+		foreach (Intersection n in points) {+			if (found) {+				return n;+			}+			+			if (n.editpoint_a == e || n.editpoint_b == e) {+				found = true;+			}+		}+		return null;+	}+	+	public Intersection? get_intersection (EditPoint e) {+		foreach (Intersection n in points) {+			if (n.editpoint_a == e || n.editpoint_b == e) {+				return n;+			}+		}+		+		return null;+	}+	+	public void append (IntersectionList i) {+		foreach (Intersection inter in i.points) {+			points.append (inter);+		}+	}++	public static IntersectionList create_intersection_list (Path p1, Path p2) {+		Path new_path = new Path ();+		IntersectionList il = new IntersectionList ();+		+		unowned List<EditPoint> a_start, a_stop;+		unowned List<EditPoint> b_start, b_stop;+		+		EditPoint e;+		+		if (p1 == p2) {+			return il;+		}+		+		a_start = p1.points.first ();+		for (int i = 0; i < p1.points.length (); i++) {+			+			if (a_start.data.next == null) {+				a_stop = p1.points.first ();+			} else {+				a_stop = a_start.data.get_next ();+			}+			+			b_start = p2.points.first ();+			for (int j = 0; j < p2.points.length (); j++) {+				+				if (b_start.data.next == null) {+					b_stop = p2.points.first ();+				} 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));+				//}+				+				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;+	}++	static IntersectionList find_intersections (EditPoint a0, EditPoint a1, EditPoint b0, EditPoint b1) {+		IntersectionList il = new IntersectionList ();+		+		double mind = double.MAX; ;+		double distance = double.MAX;+		+		Path.all_of (a0, a1, (ax, ay, at) => {+			if (at == 0 || at == 1) {+				return true;+			}+			+			Path.all_of (b0, b1, (bx, by, bt) => {+				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));+				}+				+				if (d < mind) mind = d;+				return true;+			});+			+			return true;+		});++		return il;+	}++	bool probably_intersecting (EditPoint a0, EditPoint a1, EditPoint b0, EditPoint b1) {+		if (has_intersection (a0.x, a1.x, b0.x, b1.x) && has_intersection (a0.y, a1.y, b0.y, b1.y)) {+			return true;+		}	++		if (has_intersection (a0.x, a1.x, b0.x, b1.x) && has_intersection (a0.y, a1.y, b0.y, b1.y)) {+			return true;+		}	+	+		return false;+	}+	+	/** return true if ranges does overlap */+	bool has_intersection (double a0, double a1, double b0, double b1) {+		if (a0 <= b0 <= a1 || a1 <= b0 <= a0) {+			if (a0 <= b1 <= a1 || a1 <= b1 <= a0) {+				return true;+			}+			+			if (b0 <= a1 <= b1 || b1 <= a1 <= b0) {+				return true;+			}+		}+		+		if (b0 <= a0 <= b1 || b1 <= a0 <= b0) {+			if (a0 <= a0 <= a1 || a1 <= a0 <= a0) {+				return true;+			}+			+			if (b0 <= a0 <= b1 || b1 <= a0 <= b0) {+				return true;+			}+		}+		+		return false;+	}+}++}diff --git a/src/Path.vala b/src/Path.valaindex 78b48da..b9f98f1 100644--- a/src/Path.vala+++ b/src/Path.vala@@ -47,7 +47,7 @@ class Path { 	bool no_derived_direction = false; 	bool clockwise_direction = true; -	delegate bool RasterIterator (double x, double y, double step); // iterate over each pixel at a given zoom level+	public delegate bool RasterIterator (double x, double y, double step); // iterate over each pixel at a given zoom level  	public double r = 0; 	public double g = 0;@@ -1343,11 +1343,11 @@ class Path { 	}  	// TODO: Find a clever mathematical solutions instead-	private void all_of (EditPoint start, EditPoint stop, RasterIterator iter, int steps = 400) {+	public static void all_of (EditPoint start, EditPoint stop, RasterIterator iter, int steps = 400) { 		all_of_curve (start.x, start.y, start.get_right_handle ().x (), start.get_right_handle ().y (), stop.get_left_handle ().x (), stop.get_left_handle ().y (), stop.x, stop.y, iter, steps); 	} -	private void all_of_curve (double x0, double y0, double x1, double y1, double x2, double y2, double x3, double y3, RasterIterator iter, int steps = 400) {+	private static void all_of_curve (double x0, double y0, double x1, double y1, double x2, double y2, double x3, double y3, RasterIterator iter, int steps = 400) { 		double px = x1; 		double py = y1; 		@@ -1579,13 +1579,24 @@ class Path { 	 	public Path? merge (Path p) { 		EditPoint e;-		IntersectionList il = create_intersection_list (this, p);-		+		IntersectionList il = IntersectionList.create_intersection_list (this, p);+		Path np = new Path ();+		Intersection s = new Intersection (0, 0, 1);+		EditPoint ex = points.last ().data;+		EditPoint ix = points.last ().data;+		uint offset_i = 0;+		uint offset_j;+		uint len_i = points.length ();+		int i, j;+		uint len_j;+		+		// add editpoints points on intersections  		foreach (Intersection inter in il.points) { 			e = new EditPoint (); 			get_closest_point_on_path (e, inter.x, inter.y); 			inter.editpoint_a = e;-					+			+			e = inter.editpoint_a; 			if (!has_edit_point (e)) { 				insert_new_point_on_path (e); 			}@@ -1594,213 +1605,92 @@ class Path { 			p.get_closest_point_on_path (e, inter.x, inter.y); 			inter.editpoint_b = e; 			+			e = inter.editpoint_b; 			if (!p.has_edit_point (e)) { 				p.insert_new_point_on_path (e); 			} -			print (@" inter.x $(inter.x), $(inter.y)\n"); 		} 		-		return null;-	}-+		// create a new path +		for (i = 0; i < points.length (); i++) {+			ex = points.nth (i).data; -class IntersectionList {-	public List<Intersection> points = new List<Intersection> ();-	-	public void add (Intersection i) {-		double d;-		Intersection l;-				-		if (points.length () == 0) {-			print (@"GIOT\n");-			points.append (i);-			return;-		}-		-		if (has_point (i)) {-			return;-		}-	-		l = ((!) points.last ()).data;-		d = Math.fabs (Math.sqrt (Math.pow (i.x - l.x, 2) + Math.pow (i.y - l.y, 2)));-		print (@"d $d\n");-		-		print (@"GIOT REM $(i.distance) $(l.distance)  $d\n");-		-		if (l.distance >= i.distance) {-			points.remove_link (points.last ());-			points.append (i);-			print (@"GIOT REM $(i.distance)\n");-			return;-		}--		if (d < 0.3) {-			return;-		}--		print (@"GIOT NEW $(i.distance)\n");-		points.append (i);-	}-	-	bool has_point (Intersection i) {-		foreach (Intersection n in points) {-			if (i.x == n.x && i.y == n.y) {-				return true;+			if (ex == points.first ().data && i != 0) {+				break; 			}-		}-		-		return false;-	}-	-	public void append (IntersectionList i) {-		foreach (Intersection inter in i.points) {-			points.append (inter);-		}-	}-} -class Intersection {-	public double x;-	public double y;-	public double distance;-	-	public EditPoint editpoint_a;-	public EditPoint editpoint_b;-	-	public Intersection (double x, double y, double distance) {-		this.x = x;-		this.y = y;-	}-}-	-	IntersectionList create_intersection_list (Path p1, Path p2) {-		Path new_path = new Path ();-		IntersectionList il = new IntersectionList ();-		-		unowned List<EditPoint> a_start, a_stop;-		unowned List<EditPoint> b_start, b_stop;-		-		if (p1 == p2) {-			return il;-		}-		-		a_start = p1.points.first ();-		for (int i = 0; i < p1.points.length (); i++) {-			-			if (a_start.data.next == null) {-				a_stop = p1.points.first ();-			} else {-				a_stop = a_start.data.get_next ();-			}+			// add new point for path a+			np.add_point (ex);+			ix.recalculate_linear_handles (); 			-			b_start = p2.points.first ();-			for (int j = 0; j < p2.points.length (); j++) {+			// swap paths+			if (il.has_edit_point (ex)) {+				s = (!) il.get_intersection (ex); 				-				if (b_start.data.next == null) {-					b_stop = p2.points.first ();-				} else {-					b_stop = b_start.data.get_next ();+				ex.type = PointType.CURVE;+				ex.right_handle.type = PointType.CURVE;+				ex.right_handle.angle  = s.editpoint_b.right_handle.angle;+				ex.right_handle.length = s.editpoint_b.right_handle.length;++				// read until we find ex+				for (j = 0; j < p.points.length (); j++) {+					ix = p.points.nth (j).data;+					+					if (ix == s.editpoint_b) {+						break;+					} 				} 				-				//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));-				//}-				-				b_start = b_stop;-			}-			-			a_start = a_stop;-		} +				offset_j = j + 1;+				len_j = p.points.length ();+				for (j = 0; j < p.points.length (); j++) {+					+					ix = p.points.nth ((j + offset_j) % len_j).data;+					+					// add+					ix.right_handle .move_to_coordinate (0, 0);+					np.add_point (ix);+					ix.recalculate_linear_handles ();+					+					if (il.has_edit_point (ix)) {+						s = (!) il.get_intersection (ix);+						break;+					}+					+				} -		-		foreach (Intersection inter in il.points) {-			EditPoint e = new EditPoint ();-			p1.get_closest_point_on_path (e, inter.x, inter.y);-			inter.editpoint_a = e;+				ix.type = PointType.CURVE;+				ix.right_handle.type = PointType.CURVE;+				ix.right_handle.angle  = s.editpoint_a.right_handle.angle;+				ix.right_handle.length = s.editpoint_a.right_handle.length; 					-			if (!has_edit_point (e)) {-				insert_new_point_on_path (e);-			}+				if (j == points.length ()) {+					np.close ();+					return np;+				} -			e = new EditPoint ();-			p2.get_closest_point_on_path (e, inter.x, inter.y);-			inter.editpoint_b = e;-			-			if (!p2.has_edit_point (e)) {-				p2.insert_new_point_on_path (e);-			}-		-			-			print (@" inter.x $(inter.x), $(inter.y)\n");-		}		-		return il;-	}+				// skip to next intersection+				int k;+				for (k = 0; k < points.length (); k++) {+					ix = points.nth (k).data;  -	IntersectionList find_intersections (EditPoint a0, EditPoint a1, EditPoint b0, EditPoint b1) {-		IntersectionList il = new IntersectionList ();-		-		double mind = double.MAX; ;-		double distance = double.MAX;-		-		all_of (a0, a1, (ax, ay, at) => {-			if (at == 0 || at == 1) {-				return true;-			}-			-			all_of (b0, b1, (bx, by, bt) => {-				double d = Math.fabs (Math.sqrt (Math.pow (ax - bx, 2) + Math.pow (ay - by, 2)));+					if (ix == s.editpoint_a) {+						break;+					}+				} 				-				if (d < 0.2) {-					il.add (new Intersection (ax, ay, 0));+				if (k == points.length ()) {+					return np; 				} 				-				if (d < mind) mind = d;-				return true;-			}, 200);-			-			return true;-		}, 200);-		-		print (@"FIND $mind\n");-		return il;-	}--	bool probably_intersecting (EditPoint a0, EditPoint a1, EditPoint b0, EditPoint b1) {-		if (has_intersection (a0.x, a1.x, b0.x, b1.x) && has_intersection (a0.y, a1.y, b0.y, b1.y)) {-			return true;-		}	--		if (has_intersection (a0.x, a1.x, b0.x, b1.x) && has_intersection (a0.y, a1.y, b0.y, b1.y)) {-			return true;-		}	-	-		return false;-	}-	-	/** return true if ranges does overlap */-	bool has_intersection (double a0, double a1, double b0, double b1) {-		if (a0 <= b0 <= a1 || a1 <= b0 <= a0) {-			if (a0 <= b1 <= a1 || a1 <= b1 <= a0) {-				return true;+				offset_i = 0;+				i = k; 			} 			-			if (b0 <= a1 <= b1 || b1 <= a1 <= b0) {-				return true;-			} 		} 		-		if (b0 <= a0 <= b1 || b1 <= a0 <= b0) {-			if (a0 <= a0 <= a1 || a1 <= a0 <= a0) {-				return true;-			}-			-			if (b0 <= a0 <= b1 || b1 <= a0 <= b0) {-				return true;-			}-		}-		-		return false;+		return np; 	}  }diff --git a/src/wscript b/src/wscriptindex 88320d8..f83dde7 100644--- a/src/wscript+++ b/src/wscript@@ -29,6 +29,8 @@ SUPPLEMENT_MAIN = [ 	'MenuTab.vala',
 	'MergeTool.vala',
 	'MoveTool.vala',
+	'Intersection.vala',
+	'IntersectionList.vala',
 	'IOThread.vala',
 	'OpenFontFormatWriter.vala',
 	'OpenFontFormatReader.vala',

Contact

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