Commit e5e14a7
Rewrite the experimental stroke code
Changed files (4)
modifiedlibbirdfont/EditPointHandle.valamodifiedlibbirdfont/Path.valamodifiedlibbirdfont/StrokeTool.valamodifiedlibbirdfont/Test.vala
Diff
@@ -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); @@ -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); }); } @@ -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;@@ -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); } }