Clone in a terminal:
Commit 6f84d44
Johan Mattsson - 2015-03-31T13:08:13+00:00
6f84d44afc0d94758858bde49e6c7465bacefa75johan.mattsson.m@gmail.com

Create new corners at self intersections

Changed files (4)

Diff

diff --git a/libbirdfont/ClickMap.vala b/libbirdfont/ClickMap.valaindex 9683ef6..180dff8 100644--- a/libbirdfont/ClickMap.vala+++ b/libbirdfont/ClickMap.vala@@ -17,52 +17,102 @@ using Cairo; namespace BirdFont {  public class ClickMap : GLib.Object {-	ImageSurface map;-	int width;+	public ImageSurface map;+	public int width; 	+	public double xmax;+	public double ymax;+	public double xmin;+	public double ymin;+		 	public ClickMap (int width) { 		this.width = width; 		map = new Cairo.ImageSurface (Cairo.Format.ARGB32, width, width);+		xmax = 0;+		ymax = 0;+		xmin = 0;+		ymin = 0; 	} 		 	public bool get_value (int x, int y) { 		unowned uchar[] d = map.get_data (); 		bool transparent;++		Context c;+		+		c = new Context (map);+		c.set_fill_rule (Cairo.FillRule.WINDING); 		 		if (unlikely (!(0 <= x < width && 0 <= y < width))) {-			warning ("Array index out of bounds.");+			warning (@"Array index out of bounds. x: $x  y: $y size: $width"); 			return true; 		} 		 		transparent = d[y * map.get_stride () + 4 * x + 3] == 0;-				+		 		return !transparent; 	}-		-	public void create_click_map (Path path) {+	+	bool add_point (Context c, double cx, double cy) {+		int px = (int) (width * ((cx - xmin) / (xmax - xmin)));+		int py = (int) (width * ((cy - ymin) / (ymax - ymin)));+		c.line_to (px, py);+		return true;+	}+	+	public void create_click_map (Path path, Path? counter = null) { // FIXME: clean up+		Path p; 		Context c;-				+		 		c = new Context (map); 		-		c.save ();+		if (counter == null) {+			xmax = path.xmax;+			ymax = path.ymax;+			xmin = path.xmin;+			ymin = path.ymin;+		} else {+			p = (!) counter;+			+			xmax = fmax (p.xmax, path.xmax);+			ymax = fmax (p.ymax, path.ymax);+			xmin = fmin (p.xmin, path.xmin);+			ymin = fmin (p.ymin, path.ymin);+		} 		+		c.save ();+		c.set_fill_rule (FillRule.EVEN_ODD); 		c.set_source_rgba (0, 0, 0, 1); 		c.new_path ();--		path.all_of_path ((cx, cy, ct) => {-			int px = (int) (width * ((cx - path.xmin) / (path.xmax - path.xmin)));-			int py = (int) (width * ((cy - path.ymin) / (path.ymax - path.ymin)));-			-			c.line_to (px, py);-			+		path.all_of_path ((cx, cy) => {+			add_point (c, cx, cy); 			return true; 		}, 2 * width);+		c.close_path ();	 		-		c.close_path ();-		c.fill ();+		if (counter != null) {+			c.new_path ();+		+			p = (!) counter;+			p.all_of_path ((cx, cy) => {+				add_point (c, cx, cy);+				return true;+			}, 2 * width);+			+			c.close_path ();+		} 		+		c.fill (); 		c.restore ();-	}+	}   } +static double fmin (double a, double b) {+	return a < b ? a : b;+}++static double fmax (double a, double b) {+	return a > b ? a : b;+}+	 }diff --git a/libbirdfont/EditPoint.vala b/libbirdfont/EditPoint.valaindex bc05924..b80a35a 100644--- a/libbirdfont/EditPoint.vala+++ b/libbirdfont/EditPoint.vala@@ -44,8 +44,8 @@ public class EditPoint : GLib.Object { 	public static uint DELETED = 1 << 2; 	public static uint TIE = 1 << 3; 	public static uint REFLECTIVE = 1 << 4;-	public static uint CORNER = 1 << 5;-	public static uint INTERSECTION = 1 << 6;+	public static uint INTERSECTION = 1 << 5;+	public static uint NEW_CORNER = 1 << 6; 	 	public uint flags = NONE; 	diff --git a/libbirdfont/Path.vala b/libbirdfont/Path.valaindex 375249c..d1ad243 100644--- a/libbirdfont/Path.vala+++ b/libbirdfont/Path.vala@@ -764,8 +764,7 @@ public class Path { 		if (!is_over_boundry (x, y)) { 			return false; 		}-		-		+			 		// generate a rasterized image of the object 		width = 160; 		click_map = new ClickMap (width);@@ -1667,7 +1666,7 @@ public class Path { 		int i; 		int index = 0; 		-		if (!has_deleted_point ()) { +		if (!has_deleted_point ()) { 			return path_list; 		} 		@@ -1959,6 +1958,7 @@ public class Path { 		find_intersection (h1.parent.x, h1.parent.y, h1.x, h1.y, h2.parent.x, h2.parent.y, h2.x, h2.y, out point_x, out point_y); 	} +	/** Finx intersection point for two straight lines. */ 	public static void find_intersection_point (EditPoint p1, EditPoint p2, EditPoint q1, EditPoint q2, out double point_x, out double point_y) { 		find_intersection (p1.x, p1.y, p2.x, p2.y, q1.x, q1.y, q2.x, q2.y, out point_x, out point_y); 	}diff --git a/libbirdfont/StrokeTool.vala b/libbirdfont/StrokeTool.valaindex 0f2c97b..9bae89b 100644--- a/libbirdfont/StrokeTool.vala+++ b/libbirdfont/StrokeTool.vala@@ -153,9 +153,7 @@ public class StrokeTool : Tool { 			warning ("One point."); 			stroked = new Path (); 		}-		-		remove_self_intersections (stroked);-		+ 		return stroked; 	} @@ -199,7 +197,7 @@ public class StrokeTool : Tool {  		stroked.recalculate_linear_handles (); 		-		return stroked;+		return remove_intersections (stroked); 	}  	static void move_segment (EditPoint stroke_start, EditPoint stroke_stop, double thickness) {@@ -253,94 +251,167 @@ public class StrokeTool : Tool { 		corner = new EditPoint (corner_x, corner_y, previous.type); 		corner.convert_to_line (); 		-		distance = Path.distance_to_point (corner, original);+		previous_handle.angle -= PI;+		next_handle.angle -= PI; 		+		distance = Path.distance_to_point (corner, original); 		ratio = 1.5 * fabs (stroke_width) / distance; // FIXME: cutoff parameter+		+		double r = original.get_right_handle ().angle;+		double l = original.get_left_handle ().angle;+		double angle = atan2 (sin (l - r), cos (l - r));+		+		if (false) { //FIXME: && angle > PI+			if (ratio > 1) {+				stroked.add_point (corner);	+			} else {+				cutoff1 = new EditPoint ();+				cutoff1.set_point_type (previous.type);+				cutoff1.convert_to_line ();++				cutoff2 = new EditPoint ();+				cutoff2.set_point_type (previous.type);+				cutoff2.convert_to_line (); 				-		if (ratio > 1) {-			stroked.add_point (corner);	-		} else {-			cutoff1 = new EditPoint ();-			cutoff1.set_point_type (previous.type);-			cutoff1.convert_to_line ();+				cutoff1.x = previous.x + (corner.x - previous.x) * ratio;+				cutoff1.y = previous.y + (corner.y - previous.y) * ratio; -			cutoff2 = new EditPoint ();-			cutoff2.set_point_type (previous.type);-			cutoff2.convert_to_line ();-			-			cutoff1.x = previous.x + (corner.x - previous.x) * ratio;-			cutoff1.y = previous.y + (corner.y - previous.y) * ratio;+				cutoff2.x = next.x + (corner.x - next.x) * ratio;+				cutoff2.y = next.y + (corner.y - next.y) * ratio; -			cutoff2.x = next.x + (corner.x - next.x) * ratio;-			cutoff2.y = next.y + (corner.y - next.y) * ratio;-			-			stroked.add_point (cutoff1);-			stroked.add_point (cutoff2);-		}+				cutoff1 = stroked.add_point (cutoff1);+				cutoff2 = stroked.add_point (cutoff2);+				+				cutoff1.recalculate_linear_handles ();+				cutoff2.recalculate_linear_handles ();+			}	+		}		+	}+	+	static Path remove_intersections (Path path) {+		PathList pl; +		Path remaining_points = path;+		+		add_self_intersection_points (remaining_points); -		previous_handle.angle -= PI;-		next_handle.angle -= PI;++		/*+		foreach (EditPoint p in remaining_points.points) {+				+			if ((p.flags & EditPoint.INTERSECTION) > 0) {+				p.flags = NONE;+				+				print (p.to_string ());+				//p.deleted = true;+			} +		}+			+		pl = remaining_points.process_deleted_points ();+		+		remaining_points = get_remaining_points (pl, remaining_points);+	*/+		return remaining_points; 	} -	static void remove_self_intersections (Path p) {-		bool keep = true;+	static Path get_remaining_points (PathList pl, Path old_path) {+		Path new_path; 		-		add_self_intersection_points (p);+		if (pl.paths.size == 0) {+			return old_path;+		} 	-		// FIXME: set start on non intersecting point-		foreach (EditPoint ep in p.points) {-			if ((ep.flags & EditPoint.INTERSECTION) > 0) {-				print (@"Inter $(ep)");-				keep = !keep;-			}-			-			if (!keep && (ep.flags & EditPoint.INTERSECTION) == 0) {-				ep.deleted = true;-				ep.type = PointType.CUBIC;+		new_path = new Path ();+		foreach (Path pn in pl.paths) {+			print (@"pn.points.size: $(pn.points.size)   new_path.points.size: $(new_path.points.size)\n");+			if (pn.points.size > new_path.points.size) {+				new_path = pn; 			} 		} 		-		p.remove_deleted_points ();+		print (@"after new_path: $(new_path.points.size)\n"); 		+	+		new_path.reopen ();+		new_path.create_list ();+		//new_path.close ();+		+		return new_path; 	} -	static void add_self_intersection_points (Path path) {-		Gee.ArrayList<EditPoint> n = new Gee.ArrayList<EditPoint> ();+	static bool add_self_intersection_points (Path path) {+		bool intersection = false; 		 		path.all_segments ((ep1, ep2) => { 			double ix, iy;-			EditPoint nep;-			EditPoint nep2;+			 			EditPoint p1; 			EditPoint p2;++			if (ep2 == path.get_last_point ()) {+				return false; // FIXME: LATS TO FIRST CASE+			} 			 			if (segment_intersects (path, ep1, ep2, out ix, out iy, out p1, out p2)) {-				nep = new EditPoint ();-				nep.prev = ep1;-				nep.next = ep2;-				-				nep.x = ix;-				nep.y = iy;-				-				n.add (nep);-				-				nep2 = new EditPoint ();-				nep2.prev = p1;-				nep2.next = p2;++				add_intersection (path, ep1.get_prev (), ep1, ix, iy); ++				// FIXME: last to first+				add_intersection (path, p1, p2, ix, iy);  				-				nep2.x = ix;-				nep2.y = iy;+				intersection = true; 				-				n.add (nep2);+				return false; 			} 			 			return true; 		}); 		+		return intersection;+	}+	+	static void add_intersection (Path path, EditPoint prev, EditPoint next, double px, double py) {+		Gee.ArrayList<EditPoint> n = new Gee.ArrayList<EditPoint> ();+		EditPoint ep1 = new EditPoint ();+		EditPoint ep2 = new EditPoint ();+		EditPoint ep3 = new EditPoint ();+		+		ep1.prev = prev;+		ep1.next = ep2;+		ep1.flags |= EditPoint.INTERSECTION;+		ep1.type = PointType.CUBIC;+		ep1.x = px;+		ep1.y = py;+		n.add (ep1);++		ep2.prev = ep1;+		ep2.next = ep3;+		ep2.flags |= EditPoint.NEW_CORNER;+		ep2.type = PointType.CUBIC;+		ep2.x = px;+		ep2.y = py;+		n.add (ep2);++		ep3.prev = ep2;+		ep3.next = next;+		ep3.flags |= EditPoint.INTERSECTION;+		ep3.type = PointType.CUBIC;+		ep3.x = px;+		ep3.y = py;+		n.add (ep3);+						+		print ("NEW:\n"); 		foreach (EditPoint np in n) {-			path.insert_new_point_on_path (np, -1, true);-			np.type = PointType.QUADRATIC;-			np.flags |= EditPoint.INTERSECTION;+			np = path.add_point_after (np, np.prev);+			path.create_list ();+			+			print ("\n");+			if  (np.prev != null && np.next != null) {+				print (np.get_prev ().to_string ());+				print (np.to_string ());+				print (np.get_next ().to_string ());+			} 		}+		+		path.recalculate_linear_handles (); 	}  	static bool segment_intersects (Path path, EditPoint ep, EditPoint next,@@ -360,30 +431,38 @@ public class StrokeTool : Tool { 		} 		 		// FIXME: last to first-		for (int i = 1; i < path.points.size - 2; i++) {+		for (int i = 2; i < path.points.size - 2; i++) { 			p1 = path.points.get (i - 1); 			p2 = path.points.get (i); 			 			Path.find_intersection_point (ep, next, p1, p2, out cross_x, out cross_y); 	-			if ((p1.x < cross_x < p2.x || p1.x > cross_x > p2.x)-				&& (p1.y < cross_y < p2.y || p1.y > cross_y > p2.y)-				&& (ep.x < cross_x < next.x || ep.x > cross_x > next.x)-				&& (ep.y < cross_y < next.y || ep.y > cross_y > next.y)) {+			if (Glyph.CANVAS_MIN < cross_x < Glyph.CANVAS_MAX+				&& Glyph.CANVAS_MIN < cross_y < Glyph.CANVAS_MAX) {++				if (!((ep.x == cross_x && ep.y == cross_y)+					|| (next.x == cross_x && next.y == cross_y)+					|| (p1.x == cross_x && p1.y == cross_y) +					|| (p2.x == cross_x && p2.y == cross_y))) {++					// iterate to find intersection.					+					ix = cross_x;+					iy = cross_y; 					-				// iterate to find intersection.					-				ix = cross_x;-				iy = cross_y;-				-				ia = p1;-				ib = p2;-				-				return true;+					ia = p1;+					ib = p2;+					+					return true;+				} 			} 		} 		 		return false; 	}+	+	static bool is_line (double x1, double y1, double x2, double y2, double x3, double y3) {+		return 0.001 < (x2 - x1) * (x3 - x1 ) + (y2 - y1) * (y3 - y1) < 0.001;+	} }  }

Contact

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