Clone in a terminal:
Commit e5e14a7
Johan Mattsson - 2014-07-18T05:54:51+00:00
e5e14a71ca83dcc4f236e70857556544e3b332c2johan.mattsson.m@gmail.com

Rewrite the experimental stroke code

Changed files (4)

Diff

diff --git a/libbirdfont/EditPointHandle.vala b/libbirdfont/EditPointHandle.valaindex dd82f2d..cff1064 100644--- a/libbirdfont/EditPointHandle.vala+++ b/libbirdfont/EditPointHandle.vala@@ -145,6 +145,10 @@ public class EditPointHandle : GLib.Object { 		return parent.get_left_handle () == this; 	} +	public void move_to_coordinate_delta (double dx, double dy) {+		move_to_coordinate_internal (px () + dx, py () + dy);+	}+	 	public void move_to_coordinate (double x, double y) { 		move_to_coordinate_internal (x, y); 		diff --git a/libbirdfont/Path.vala b/libbirdfont/Path.valaindex 6766465..6b4eb53 100644--- a/libbirdfont/Path.vala+++ b/libbirdfont/Path.vala@@ -755,20 +755,41 @@ public class Path { 		return !(xmax <= p.xmin || ymax <= p.ymin) || (xmin >= p.xmax || ymin >= p.ymax); 	} 	+	// FIXME: DELETE?+	public EditPoint delete_first_point () {+		EditPoint r;+		int size;+		+		size = points.size;+		if (unlikely (size == 0)) {+			warning ("No points in path.");+			return new EditPoint ();+		}+		+		r = points.get (0);+		points.remove_at (0);+		+		if (size > 1) {+			r.get_next ().prev = null;+		}+		+		return r;+	}+		 	public EditPoint delete_last_point () { 		EditPoint r;-		int len;+		int size; 		-		len = points.size;-		if (unlikely (len == 0)) {+		size = points.size;+		if (unlikely (size == 0)) { 			warning ("No points in path."); 			return new EditPoint (); 		} 		-		r = points.get (len - 1);-		points.remove_at (len - 1);+		r = points.get (size - 1);+		points.remove_at (size - 1); 		-		if (len > 1) {+		if (size > 1) { 			r.get_prev ().next = null; 			 			if (r.next != null) {@@ -927,17 +948,15 @@ public class Path { 			ymin = 0; 		} -		if (stroke > 0) {-			paths = StrokeTool.get_stroke (this, stroke);-		} else {-			paths = new PathList ();-			paths.add (this);+		foreach (EditPoint p in points) {+			update_region_boundaries_for_point (p); 		}--		foreach (Path path in paths.paths) {-			foreach (EditPoint p in path.points) {-				update_region_boundaries_for_point (p);-			}+		+		if (stroke > 0) {+			xmax += stroke;+			ymax += stroke;+			xmin -= stroke;+			ymin -= stroke; 		} 	} 		@@ -1068,7 +1087,7 @@ public class Path { 			ep.y - (ep.y - prev.y) / 2);		 	} -	public void insert_new_point_on_path (EditPoint ep) {+	public void insert_new_point_on_path (EditPoint ep, double t = -1) { 		EditPoint start, stop; 		double x0, x1, y0, y1; 		double position, min;@@ -1095,17 +1114,21 @@ public class Path { 		min = double.MAX;  		position = 0.5;--		all_of (start, stop, (cx, cy, t) => {-			double n = pow (ep.x - cx, 2) + pow (ep.y - cy, 2);-			-			if (n < min) {-				min = n;-				position = t;-			}-			-			return true;-		});+		+		if (t < 0) {+			all_of (start, stop, (cx, cy, t) => {+				double n = pow (ep.x - cx, 2) + pow (ep.y - cy, 2);+				+				if (n < min) {+					min = n;+					position = t;+				}+				+				return true;+			});+		} else {+			position = t;+		} 		 		if (right == PointType.DOUBLE_CURVE || left == PointType.DOUBLE_CURVE) { 			double_bezier_vector (position, start.x, start.get_right_handle ().x, stop.get_left_handle ().x, stop.x, out x0, out x1);@@ -1283,7 +1306,7 @@ public class Path { 		edit_point.set_position (ox, oy); 	} -	public static void all_of (EditPoint start, EditPoint stop, RasterIterator iter, int steps = -1) {+	public static bool all_of (EditPoint start, EditPoint stop, RasterIterator iter, int steps = -1) { 		PointType right = PenTool.to_curve (start.get_right_handle ().type); 		PointType left = PenTool.to_curve (stop.get_left_handle ().type); 		@@ -1292,15 +1315,15 @@ public class Path { 		} 		 		if (right == PointType.DOUBLE_CURVE || left == PointType.DOUBLE_CURVE) {-			all_of_double (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);+			return all_of_double (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); 		} else if (right == PointType.QUADRATIC && left == PointType.QUADRATIC) {-			all_of_quadratic_curve (start.x, start.y, start.get_right_handle ().x, start.get_right_handle ().y, stop.x, stop.y, iter, steps);+			return all_of_quadratic_curve (start.x, start.y, start.get_right_handle ().x, start.get_right_handle ().y, stop.x, stop.y, iter, steps); 		} else if (right == PointType.CUBIC && left == PointType.CUBIC) {-			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);-		} else {-			warning (@"Mixed point types in segment $(start.x),$(start.y) to $(stop.x),$(stop.y)");-			all_of_quadratic_curve (start.x, start.y, start.get_right_handle ().x, start.get_right_handle ().x, stop.x, stop.y, iter, steps);+			return 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); 		}+		+		warning (@"Mixed point types in segment $(start.x),$(start.y) to $(stop.x),$(stop.y)");+		return all_of_quadratic_curve (start.x, start.y, start.get_right_handle ().x, start.get_right_handle ().x, stop.x, stop.y, iter, steps); 	}  	public static void get_point_for_step (EditPoint start, EditPoint stop, double step, out double x, out double y) {@@ -1309,7 +1332,7 @@ public class Path { 		y = bezier_path (step, start.y, start.get_right_handle ().y, stop.get_left_handle ().y, stop.y);	 	} -	private static void all_of_double (double x0, double y0, double x1, double y1, double x2, double y2, double x3, double y3, RasterIterator iter, double steps = 400) {+	private static bool all_of_double (double x0, double y0, double x1, double y1, double x2, double y2, double x3, double y3, RasterIterator iter, double steps = 400) { 		double px = x1; 		double py = y1; 		@@ -1329,7 +1352,7 @@ public class Path { 			double_step = t / 2; 			 			if (!iter (px, py, double_step)) {-				return;+				return false; 			} 			 		}@@ -1343,13 +1366,14 @@ public class Path { 			double_step = 0.5 + t / 2; 			 			if (!iter (px, py, double_step)) {-				return;+				return false; 			}-			-		}		+		}	+		+		return true;	 	} 		-	private static void all_of_quadratic_curve (double x0, double y0, double x1, double y1, double x2, double y2, RasterIterator iter, double steps = 400) {+	private static bool all_of_quadratic_curve (double x0, double y0, double x1, double y1, double x2, double y2, RasterIterator iter, double steps = 400) { 		double px = x1; 		double py = y1; 		@@ -1362,13 +1386,14 @@ public class Path { 			py = quadratic_bezier_path (t, y0, y1, y2); 			 			if (!iter (px, py, t)) {-				return;+				return false; 			}-			-		}			+		}+		+		return true; 	} -	private static void all_of_curve (double x0, double y0, double x1, double y1, double x2, double y2, double x3, double y3, RasterIterator iter, double steps = 400) {+	private static bool all_of_curve (double x0, double y0, double x1, double y1, double x2, double y2, double x3, double y3, RasterIterator iter, double steps = 400) { 		double px = x1; 		double py = y1; 		@@ -1381,34 +1406,38 @@ public class Path { 			py = bezier_path (t, y0, y1, y2, y3); 			 			if (!iter (px, py, t)) {-				return;+				return false; 			}-			-		}	+		}+		+		return true; 	} -	public void all_segments (SegmentIterator iter) {+	public bool all_segments (SegmentIterator iter) { 		unowned EditPoint i, next; 		 		if (points.size < 2) {-			return;+			return false; 		}  		for (int j = 0; j < points.size - 1; j++) { 			i = points.get (j).get_link_item (); 			next = i.get_next ();-			iter (i, next);+			if (!iter (i, next)) {+				return false;+			} 		} 		 		if (!is_open ()) {-			iter (points.get (points.size - 1), points.get (0));-		}		+			return iter (points.get (points.size - 1), points.get (0));+		}+		+		return true; 	}  	public void all_of_path (RasterIterator iter, int steps = -1) { 		all_segments ((start, stop) => {-			all_of (start, stop, iter, steps);-			return true;+			return all_of (start, stop, iter, steps); 		}); 	} 	diff --git a/libbirdfont/StrokeTool.vala b/libbirdfont/StrokeTool.valaindex 3247993..d9322ee 100644--- a/libbirdfont/StrokeTool.vala+++ b/libbirdfont/StrokeTool.vala@@ -42,8 +42,6 @@ public class StrokeTool : Tool { 		 		foreach (Path p in g.active_paths) { 			paths.append (get_stroke (p, p.stroke));-			paths.add (add_tangent_points (p));-			paths.add (p.get_quadratic_points ()); 		} 		 		foreach (Path np in paths.paths) {@@ -51,7 +49,16 @@ public class StrokeTool : Tool { 		} 	} 	-	public static PathList get_stroke (Path p, double thickness) {+	public static PathList get_stroke (Path path, double thickness) {+		Path p = path.copy ();+		PathList pl;++		pl = get_stroke_outline (p, thickness);	+		+		return pl;	+	}+	+	public static PathList get_stroke_outline (Path p, double thickness) { 		Path counter, outline, merged; 		PathList paths = new PathList (); 				@@ -130,33 +137,34 @@ public class StrokeTool : Tool { 			warning ("Missing points."); 			return stroke; 		}-		+				 		// 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;		+		corner1.x = end.x + cos (angle - PI / 2) * thickness;+		corner1.y = end.y + sin (angle - PI / 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;+		corner2.x = end.x + cos (angle + PI / 2) * thickness;+		corner2.y = end.y + sin (angle + PI / 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;		+		corner3.x = end.x + cos (angle + PI / 2) * thickness;+		corner3.y = end.y + sin (angle + PI / 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;+		corner4.x = end.x + cos (angle - PI / 2) * thickness;+		corner4.y = end.y + sin (angle - PI / 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 ();+		corner1.get_left_handle ().convert_to_line ();+		corner2.get_right_handle ().convert_to_line ();+		+		corner3.get_left_handle ().convert_to_line ();+		corner4.get_right_handle ().convert_to_line (); 				 		counter.reverse (); @@ -168,18 +176,17 @@ public class StrokeTool : Tool { 		merged.close (); 		merged.create_list (); 		merged.recalculate_linear_handles ();-								+		+		// DELETE merged.get_first_point ().get_right_handle ().move_to_coordinate (0, 0);+							 		return merged; 	} 	 	static Path create_stroke (Path p, double thickness) {-		Path new_path; 		Path stroked; 		-		new_path = add_tangent_points (p);-		-		if (new_path.points.size >= 2) {-			stroked = change_stroke_width (new_path, thickness);+		if (p.points.size >= 2) {+			stroked = change_stroke_width (p, thickness); 			 			if (!p.is_open ()) { 				stroked.reverse ();@@ -203,113 +210,23 @@ public class StrokeTool : Tool { 		return false; 	} -	static Path add_tangent_points (Path p) {-		Path path;-		int steps = 2;-		Gee.ArrayList<EditPoint> new_points = new Gee.ArrayList<EditPoint> ();-		-		EditPoint nep;-		EditPoint? previous = null;-		-		path = (has_double_points (p)) ? -			p.get_quadratic_points () : p.copy ();-		-		path.all_segments ((start, stop) => {-			EditPoint? prev = null;-			double length = Path.get_length_from (start, stop);-			-			steps = (int) (length / 10);--			if (start.type == PointType.DOUBLE_CURVE || stop.type == PointType.DOUBLE_CURVE) {-				warning ("Invalid point type.");-			}-			-			if (steps > 1) {-				Path.all_of (start, stop, (x, y, step) => {-					EditPoint ep = new EditPoint ();--					if (0 < step < 1) {-						ep.set_position (x, y);-						-						// Stop processing when the first hidden point is found.-						if (start.type == PointType.HIDDEN || stop.type == PointType.HIDDEN) {-							// FIXME: Rename tracker points -							return true;-						}-						-						return_val_if_fail (prev != null, false);--						ep.prev = ((!) prev).get_link_item ();-						ep.next = start.get_next ();-						-						ep.type = PenTool.to_curve (start.type);-						-						if (unlikely (ep.next == null || ep.prev == null)) {-							warning ("No points on segment.");-							return false;-						}--						new_points.add (ep);-					}-					-					if (step <= 0) {-						prev = start;-						new_points.add (start);-					} else if (step >= 1) {-						prev = stop;-						new_points.add (stop);-					} else {-						prev = ep;-					}-					-					return true;-				}, steps);				-			}-			-			return true;-		});-	-		while (new_points.size > 0) {-			nep = new_points.get (0);-			-			if (previous != null) {-				nep.prev = ((!) previous).get_link_item ();-			}-			-			if (!path.has_point (nep)) {-				return_if_fail (nep.prev != null);				-				path.insert_new_point_on_path (nep);-			}-			-			previous = nep;--			new_points.remove_at (0);-			path.create_list ();-		}-		-		path.create_list ();-		-		return path;-	}--	/** Shrink or expand the outline. */ 	static Path change_stroke_width (Path new_path, double thickness) { 		double px, py, nx, ny, dnx, dny, counter_dnx, counter_dny;	 		double space_left, space_right; 		Path stroked = new Path ();		 		EditPoint ep; 		bool clockwise;-		bool end_point; // first and last point 		uint k; 		uint npoints; 		double distance_to_counter, distance_to_path; 		PointSelection ps; 		double handle_x, handle_y; 		EditPointHandle h1, h2;-				-		clockwise = new_path.is_clockwise (); 		-		end_point = true;+		new_path.remove_points_on_points ();+		+		clockwise = new_path.is_clockwise ();+ 		k = 0; 		npoints = new_path.points.size; 		@@ -318,248 +235,222 @@ public class StrokeTool : Tool { 			return new_path; 		} 		-		foreach (EditPoint e in new_path.points) {-			ep = e.copy ();-			-			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++;-			-			px = ep.x;-			py = ep.y;-			-			if (!end_point) {-				ep.x += dnx;-				ep.y += dny;-			}-			-			if (ep.type == PointType.HIDDEN) {-				break;-			}-			-			nx = ep.x;-			ny = ep.y;-			-			space_left = get_space_difference (new_path, e, e.get_prev (), thickness, clockwise);-			space_right = get_space_difference (new_path, e, e.get_next (), thickness, clockwise);+		Test test = new Test.time ("change_stroke_width");+		test.timer_start (); 		-			distance_to_counter = Path.distance (nx, px + counter_dnx, ny, py + counter_dny);-			distance_to_path = Path.distance (px, nx, py, ny);-			-			if (new_path.is_open () && end_point) {-				// open end point-				stroked.add (e.x, e.y);-			} else {-				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");-				}-			}-		}+		EditPoint start, stop, new_start;+		EditPoint stroke_start, stroke_stop, middle;+		EditPointHandle r, l;+		double left_x, left_y;+		bool new_point = false; 		-		// FIXME. remove?-		stroked.get_first_point ().set_point_type (stroked.get_first_point ().get_next ().type);-		stroked.get_last_point ().set_point_type (stroked.get_last_point ().get_prev ().type);+		left_x = 0;+		left_y = 0;+		start = new_path.get_first_point ();+		int it = 0; 		-		stroked.create_list ();-		foreach (EditPoint e in stroked.points) {-			e.recalculate_linear_handles ();-		} 		-		foreach (EditPoint e in stroked.points) {-			if (e.type == PointType.QUADRATIC && e.next != null) {-				h1 = e.get_right_handle ();-				h2 = e.get_next ().get_left_handle ();-				Path.find_intersection_handle (h1, h2, out handle_x, out handle_y);-				// FIXME:-				//h1.move_to_coordinate_internal (handle_x, handle_y);						-				//h2.move_to_coordinate_internal (handle_x, handle_y);+		bool bad_segment = false;+		for (int points_to_process = new_path.points.size - 1; points_to_process >= 0; points_to_process--) {++			if (++it > 100) { // FIXME: delete+				warning ("Skipping the rest of the path.");+				break; 			}-		} 			-		return stroked;-	}-		-	/** Add a corner node for sharp corners. */-	static void corner_position (EditPoint ep, bool clockwise, double thickness, Path p) {-		EditPoint corner = ep.copy ();-		double x1, x3;-		double y1, y3;-		double lx1, lx2, lx3, lx4;-		double ly1, ly2, ly3, ly4;-		double k1, k2;-		double n1, n2;-		double posx, posy;-		EditPointHandle h1, h2;--		h1 = ep.get_right_handle ();-		h2 = ep.get_left_handle ();-		-		x1 = ep.x + cos (h1.angle + PI / 2) * 2 * thickness;-		y1 = ep.y + sin (h1.angle + PI / 2) * 2 * thickness;--		x3 = ep.x + cos (h2.angle - PI / 2) * 2 * thickness;-		y3 = ep.y + sin (h2.angle - PI / 2) * 2 * thickness;--		k1 = sin (h1.angle) / cos (h1.angle);-		n1 = y1;--		k2 = sin (h2.angle) / cos (h2.angle);-		n2 = y3;-		-		lx1 = -50 + x1;-		ly1 = k1 * -50 + n1;-		lx2 = 100 + x1;-		ly2 = k1 * 100 + n1;-		lx3 = -50 + x3;-		ly3 = k2 * -50 + n2;-		lx4 = 100 + x3;-		ly4 = k2 * 100 + n2;--		Path.find_intersection (lx1, ly1, lx2, ly2, lx3, ly3, lx4, ly4, out posx, out posy);-		-		corner.x = posx;-		corner.y = posy;--		if (Path.distance (ep.x, posx, ep.y, posy) > fabs (10 * thickness)) {-			add_corner_end (ep, p, x3, y3);-		} else {-			p.add_point (corner);-		}-	}--	// TODO: elaborated stroke endings-	static void add_corner_end (EditPoint e, Path path, double next_x, double next_y) {-		EditPoint ep;-		double px = e.x + (e.x - next_x) / 2;-		double py = e.y + (e.y - next_y) / 2;-		ep = path.add (px, py);-		ep.set_point_type (ep.get_prev ().type);-		ep.get_right_handle ().convert_to_line ();-		ep.get_left_handle ().convert_to_line ();-		ep.recalculate_linear_handles ();-	}--	/** Sharp corner that need two extra points to be built. */-	public static void add_corner_nodes (Path path, Path stroked, EditPoint e, bool clockwise, double thickness, bool end_point, double nx, double ny) {-		EditPoint corner1, corner2, swap_corner;-		-		// add new points in order to preserve the stroke-		corner1 = e.copy ();-		stroked.add_point (corner1);-	-		corner2 = e.copy ();-		-		stroked.get_closest_point_on_path (corner2, nx, ny); // FIXME: optimize--		if (end_point) {-			swap_corner = corner1;-			corner1 = corner2;-			corner2 = swap_corner;-		}+			if (is_null (start) || start.next == null) {+				warning ("No next point");+				break;+			}+			+			stop = start.get_next (); -		if (end_point) {-			stroked.insert_new_point_on_path (corner1);-		} else {-			stroked.insert_new_point_on_path (corner2);-		}+			// move point+			stroke_start = start.copy ();+			stroke_stop = stop.copy (); 		-		corner1.x += cos (e.get_right_handle ().angle + PI / 2) * 2 * thickness;-		corner1.y += sin (e.get_right_handle ().angle + PI / 2) * 2 * thickness;--		corner2.x += cos (e.get_left_handle ().angle - PI / 2) * 2 * thickness;-		corner2.y += sin (e.get_left_handle ().angle - PI / 2) * 2 * thickness;--		// fill the gap-		// FIXME: this should move the point not create a new point-		if (!path.is_open () || (path.is_open () && !end_point)) {-			corner_position (e, clockwise, thickness, stroked);-		} -	}--	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 (ps, clockwise, thickness, out sx, out sy);-		strokex = sx + ps.point.x;-		strokey = sy + ps.point.y;	-	}+			stroke_start.set_tie_handle (false);+			stroke_stop.set_tie_handle (false);+			+			start.set_tie_handle (false);+			stop.set_tie_handle (false);+						+			// from last segment+			//if (!new_point) {+				stroke_start.get_left_handle ().move_to_coordinate_delta (left_x, left_y);+			//}+			+			r = stroke_start.get_right_handle ();+			l = stroke_stop.get_left_handle ();+			+			double m = cos (r.angle + PI / 2) * thickness;+			double n = sin (r.angle + PI / 2) * thickness;+			+			stroke_start.independent_x += m;+			stroke_start.independent_y += n;+			+			middle = new EditPoint ();+			middle.x = r.x;+			middle.y = r.y;+			middle.get_right_handle ().move_to_coordinate (l.x, l.y);+			+			double o = cos (middle.get_right_handle ().angle - PI / 2) * thickness;+			double p = sin (middle.get_right_handle ().angle - PI / 2) * thickness;+			+			// DELETE print (@"M $m n $n o $o p $p\n");			+			stroke_start.get_right_handle ().move_to_coordinate_delta (m , n);+			//stroke_start.get_right_handle ().move_to_coordinate_delta (o, p); -	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 la = l.angle;+			double qx = cos (la - PI / 2) * thickness;+			double qy = sin (la - PI / 2) * thickness;+			+			// DELETE  print (@"o $o p $p qx $qx qy $qy\n"); 			-			double m, n, o, p;-			double ldnx, ldny;+			left_x = qx;+			left_y = qy;+			stroke_stop.get_left_handle ().move_to_coordinate_delta (left_x, left_y); 			-			bool end_node = ps.is_first () || ps.is_last ();-			EditPoint e = ps.point;+			stroke_stop.independent_x += qx;+			stroke_stop.independent_y += qy;++			// add points if the stroke is at wring distance from path+			Gee.ArrayList<EditPoint> on_stroke = new Gee.ArrayList<EditPoint> ();+			int n_samples = 0;+			Path.all_of (stroke_start, stroke_stop, (x, y, t) => {+				if (t == 0) {+					return true;+				}+				+				if (n_samples >= 2) {+					return false;+				}+				+				on_stroke.add (new EditPoint (x, y));+				n_samples++;+				return true;+			}, 3); 			-			if (!end_node) {-				e.recalculate_linear_handles ();+			if (on_stroke.size != 2) {+				warning (@"on_stroke.size: $(on_stroke.size)");+				return stroked; 			} 			-			ra = e.get_right_handle ().angle;-			la = e.get_left_handle ().angle;+			int i = 0; 			-			avg_angle = (la + ra + PI) / 2.0;+			new_point = false;+			EditPoint split_point = new EditPoint ();+			Path.all_of (start, stop, (x, y, t) => {+				double d;+				double dx, dy;+				EditPoint point_on_stroke;+				double stroke_width = fabs (thickness);+				+				if (t == 0) {+					return true;+				}+				+				if (i >= on_stroke.size) {+					warning ("Out of bounds.");+					return false;+				}+				+				point_on_stroke = on_stroke.get (i++); +				+				d = fabs (Path.distance (point_on_stroke.x, x, point_on_stroke.y, y) - stroke_width);+				dx = fabs (point_on_stroke.x - x);+				dy = fabs (point_on_stroke.y - y);+				+				print (@"CUT d $d   x $x on_stroke.x $(point_on_stroke.x) y $y   on_stroke.y $(point_on_stroke.y) thick $thickness\n");+				+				print (@"d $d \n");+				+				if (d > 1) {+					print ("err...");+					+					if (!bad_segment) {+						Path.all_of (start, stop, (x, y, t) => {+							new_path.insert_new_point_on_path_at (x, y);+							return true;+						}, 10);+						+						bad_segment = true;+					}+					+				} else if (d > 0.1) {+					split_point = new EditPoint (x, y);+					+					split_point.prev = start;+					split_point.next = stop;+					+					start.next = split_point;+					stop.prev = split_point;+					+					if (start.x == split_point.x && start.y == split_point.y) {+						warning (@"Back again?  $d");+						return false;+					} else {+						new_path.insert_new_point_on_path (split_point);+						new_point = true;+					}+					+					bad_segment = false;+				} else {+					bad_segment = false;+				} -			while (avg_angle > 2 * PI) {-				avg_angle -= 2 * PI;+				return !new_point;+			}, 3);+			+			if (!new_point) {+				stroked.add_point (stroke_start.copy ());+				new_start = stop; // or inserted point+			} else if (bad_segment) {+				stroked.add_point (stroke_start.copy ());+				points_to_process += 10; // redo the current one plus the new point+				new_start = stop;+			} else {+				+				la = split_point.get_left_handle ().angle;+				qx = cos (la - PI / 2) * thickness;+				qy = sin (la - PI / 2) * thickness;+				+				// DELETE print (@"o $o p $p qx $qx qy $qy\n");+				+				left_x = qx;+				left_y = qy;+			+				points_to_process += 2; // redo the current one plus the new point+				new_start = start; 			}-									-			angle = avg_angle - PI / 2; 			-			m = cos (ra + PI / 2) * thickness;-			n = sin (ra + PI / 2) * thickness;+			// DELETE print (@"next $(start.x), $(start.y)\n"); 			-			o = cos (la - PI / 2) * thickness;-			p = sin (la - PI / 2) * thickness;+			start = new_start;+		}+		+		stroked.set_stroke (0);+		+		if (new_path.points.size > 2 && stroked.points.size > 2) {+			//stroked.delete_last_point (); -			ldnx = m + o;-			ldny = n + p;+			l = new_path.get_last_point ().get_left_handle (); -			if (end_node) {-				strokex = 0;-				strokey = 0;-			} else {-				strokex = ldnx;-				strokey = ldny;-			}-	}-	-	static double get_space_difference (Path p, EditPoint ep0, EditPoint ep1, double stroke, bool clockwise) {-		double p0x, p0y, p1x, p1y;-		double d1, d2;+			stroked.get_last_point ().get_left_handle ().angle = l.angle;+			stroked.get_last_point ().get_left_handle ().length = l.length;+			stroked.get_last_point ().get_left_handle ().type = l.type;+			+			stroked.get_last_point ().get_right_handle ().convert_to_line ();+			stroked.get_first_point ().get_left_handle ().convert_to_line ();+		} 		-		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);+		// adjust last angle here. 		-		d1 = Path.distance (ep0.x, ep1.x, ep0.y, ep1.y);-		d2 = Path.distance (p0x, p1x, p0y, p1y);+		test.print (); 		-		return d2 - d1;+		return stroked; 	}-+	 	public static double length_adjustment (double lx, double ldx, double ly, double ldy, double l) { 		double a = sqrt (pow (ldx, 2) + pow (ldy, 2)) / fabs (l);	 		return a;diff --git a/libbirdfont/Test.vala b/libbirdfont/Test.valaindex a9be9a3..0474843 100644--- a/libbirdfont/Test.vala+++ b/libbirdfont/Test.vala@@ -17,28 +17,33 @@ namespace BirdFont { class Test : Object { 	public Callback callback; 	public string name;-	double time;+	double time_stamp; 	bool benchmark = false; 	+	public Test.time (string name) {+		this.name = name;+		benchmark = true;+	}+	 	public Test (Callback callback, string name, bool benchmark = false) { 		this.callback = callback; 		this.name = name;-		this.time = 0;+		this.time_stamp = 0; 		this.benchmark = benchmark; 	} 	 	public void timer_start () {-		time = GLib.get_real_time ();+		time_stamp = GLib.get_real_time (); 	}  	public void timer_stop () { 		double stop_time = GLib.get_real_time (); 		print_time ("Timer stop after", stop_time);-		time = stop_time - time;+		time_stamp = stop_time - time_stamp; 	} 	 	public double get_time () {-		return time / 1000000.0;+		return time_stamp / 1000000.0; 	} 	 	public bool is_benchmark () {@@ -47,7 +52,11 @@ class Test : Object { 	 	public static void print_time (string mess, double start_time) { 		double stop_time = GLib.get_real_time ();-		print (@"$mess $((stop_time - start_time) / 1000000.0)s\n");+		stdout.printf (@"$mess $((stop_time - start_time) / 1000000.0)s\n");+	}+	+	public void print () {+		print_time (name, time_stamp); 	} } 

Contact

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