Commit 504952a
More multimaster code
Changed files (6)
modifiedlibbirdfont/EditPointHandle.valamodifiedlibbirdfont/Glyph.valamodifiedlibbirdfont/GlyphCollection.valamodifiedlibbirdfont/OverviewTools.valamodifiedlibbirdfont/Path.valamodifiedlibbirdfont/StrokeTool.vala
Diff
@@ -314,6 +314,11 @@ public class EditPointHandle : GLib.Object { double x = (cos (angle1) + cos (angle2)) / 2; double y = (sin (angle1) + sin (angle2)) / 2; handle.move_to_coordinate (x, y);+ + if (fabs (x) < 0.001 && fabs (y) < 0.001) {+ return (angle1 + PI / 2) % 2 * PI;+ }+ return handle.angle; } @@ -2445,35 +2445,28 @@ public class Glyph : FontDisplay { } public Glyph self_interpolate (double weight) {- Glyph g = copy ();- g.fix_curve_orientation ();- g.layers = new Layer (); // remove all paths+ Glyph g1 = copy ();+ Glyph g2 = copy (); - foreach (Path p in get_visible_paths ()) {+ g1.fix_curve_orientation ();+ g2.layers = new Layer (); // remove all paths+ + foreach (Path p in g1.get_visible_paths ()) { bool counter = !p.is_clockwise ();+ //g2.add_path (p.self_interpolate (weight, counter));++ g2.add_path (p.copy ()); - g.add_path (p.copy ());+ p.remove_points_on_points (); Path master = p.get_self_interpolated_master (counter);- g.add_path (master);+ p = p.interpolate_estimated_path (master, weight);+ p.recalculate_linear_handles (); - g.add_path (p.interpolate_estimated_path (master, weight));+ g2.add_path (p);+ g2.add_path (master); } - return g;- }- - public Glyph self_interpolate_fast (double weight) {- Glyph g = copy ();- g.fix_curve_orientation ();- g.layers = new Layer (); // remove all paths- - foreach (Path p in get_visible_paths ()) {- bool counter = !p.is_clockwise ();- Path path = p.self_interpolate_fast (weight, counter);- g.add_path (path);- }- - return g;+ return g2; } } @@ -158,7 +158,8 @@ public class GlyphCollection : GLib.Object { } if (glyph_masters.size == 1) {- return get_current ().self_interpolate_fast (weight);+ //return get_current ().self_interpolate_fast (weight);+ return get_current (); } else { warning("Not implemented."); }@@ -157,8 +157,8 @@ public class OverviewTools : ToolCollection { master_size.set_big_number (false); master_size.set_int_value ("0.000"); master_size.set_int_step (1);- master_size.set_min (-2);- master_size.set_max (2);+ master_size.set_min (-1);+ master_size.set_max (1); master_size.show_icon (true); master_size.set_persistent (false); master_size.new_value_action.connect ((self) => {@@ -2634,23 +2634,6 @@ public class Path : GLib.Object { } } - public EditPoint get_closest_point (double x, double y) {- double min = Glyph.CANVAS_MAX;- double d; - EditPoint p = new EditPoint (Glyph.CANVAS_MAX, Glyph.CANVAS_MAX);- - foreach (EditPoint ep in points) {- d = distance (x, ep.x, y, ep.y); -- if (d < min) {- min = d;- p = ep;- }- }- - return p;- }- public Path self_interpolate (double weight, bool counter) { Path master; Path p = new Path ();@@ -2671,26 +2654,22 @@ public class Path : GLib.Object { return p; }- - public Path self_interpolate_fast (double weight, bool counter) {- return StrokeTool.change_weight_fast (this, 5 * weight, counter);- }- - static double abs_max (double a, double b) {- return fabs (a) > fabs (b) ? a : b;- } public Path interpolate_estimated_path (Path master, double weight) { Path p = copy (); EditPoint ep, master_point;- EditPointHandle h;- double length; double x, y; + if (p.points.size <= 1 || master.points.size <= 1) {+ return p;+ }+ master_point = new EditPoint (); for (int i = 0; i < p.points.size; i++) { ep = p.points.get (i);+ + bool debug = (-19 < ep.x < -21) && (39 < ep.y < 41); double right_angle = ep.get_right_handle ().angle; double left_angle = ep.get_left_handle ().angle;@@ -2698,32 +2677,137 @@ public class Path : GLib.Object { angle += PI; angle %= 2 * PI; - x = ep.x + 5 * cos (angle);- y = ep.y + 5 * sin (angle);+ double close_x, close_y;+ double min_distance = Glyph.CANVAS_MAX;+ double distance;+ double distance_to_edge = (5 / 2.0) * weight; - master_point = new EditPoint ();- master.get_closest_point_on_path (master_point, x, y);- master_point.color = Color.red ();- master.insert_new_point_on_path (master_point);+ close_x = Glyph.CANVAS_MAX;+ close_y = Glyph.CANVAS_MAX; - ep.x += (master_point.x - ep.x) * weight;- ep.y += (master_point.y - ep.y) * weight;+ while (Path.distance (close_x, master_point.x, close_y, master_point.y) > 0.1) {+ x = ep.x + distance_to_edge * cos (angle);+ y = ep.y + distance_to_edge * sin (angle);+ + if (debug) {+ print(@"Search $x $y\n");+ }+ + master_point = new EditPoint ();+ master.get_closest_point_on_path (master_point, x, y);+ master_point.color = Color.red ();+ master.insert_new_point_on_path (master_point);+ master_point.get_right_handle ().angle = angle;+ + distance_to_edge += 0.1;+ + distance = Path.distance (x, master_point.x, y, master_point.y);+ if (distance < min_distance) {+ min_distance = distance;+ close_x = x;+ close_y = y;+ }+ + if (distance_to_edge > 5) {+ break;+ }+ } -/*- h = ep.get_right_handle ();- h.length += 5 * weight;+ x = close_x;+ y = close_x; - h = ep.get_left_handle ();- h.length += 5 * weight;- */+ ep.x += (master_point.x - ep.x) * weight;+ ep.y += (master_point.y - ep.y) * weight; } + p.adjust_interpolated_handles (master, fabs ((5 / 2.0) * weight));+ return p; } public Path get_self_interpolated_master (bool counter) { return StrokeTool.change_weight (this, counter); }+ + void adjust_interpolated_handles (Path master, double edge) {+ EditPoint ep, next;++ for (int i = 0; i < points.size; i++) {+ ep = points.get (i);+ next = points.get (i % points.size);+ adjust_interpolated_handle (master, ep, next, edge);+ }+ }++ void adjust_interpolated_handle (Path master, + EditPoint ep, EditPoint next,+ double edge) { + + double x, y;+ double next_length_adjustment = 0;+ double prev_length_adjustment_reverse = 0;+ + double min_distortion = double.MAX;++ EditPoint master_point = new EditPoint ();+ + get_point_for_step (ep, next, 0.55, out x, out y);+ master.get_closest_point_on_path (master_point, x, y);++ double tolerance = 0.01;+ double start_length = ep.get_right_handle ().length;+ double stop_length = next.get_left_handle ().length;+ + EditPoint ep1, ep2;+ + ep1 = ep.copy ();+ ep2 = next.copy ();+ + double total_distance = Path.distance (ep1.x, ep2.x, ep1.y, ep2.y);+ + for (double m = 50.0; m >= tolerance / 2.0; m /= 10.0) {+ double step = m / 10.0;+ min_distortion = double.MAX;+ + double first = (m == 50.0) ? 0 : -m;+ + for (double a = first; a < m; a += step) {+ for (double b = first; b < m; b += step) {++ if (start_length + a + stop_length + b > total_distance) {+ break;+ }+ + ep1.get_right_handle ().length = start_length + a;+ ep2.get_left_handle ().length = stop_length + b;++ get_point_for_step (ep1, ep2, 0.55, out x, out y);+ double error = distance (master_point.x, x, master_point.y, y);+ error = fabs(error - edge); + + if (error < min_distortion+ && start_length + a > 0+ && stop_length + b > 0) {+ min_distortion = error;+ prev_length_adjustment_reverse = a;+ next_length_adjustment = b;+ }+ }+ }+ + start_length += prev_length_adjustment_reverse;+ stop_length += next_length_adjustment;+ }+ + ep.get_right_handle ().length = start_length;+ + if (ep.get_right_handle ().type != PointType.QUADRATIC) {+ next.get_left_handle ().length = stop_length;+ } else {+ next.get_left_handle ().move_to_coordinate (+ ep.get_right_handle ().x, ep.get_right_handle ().y);+ }+ } } }@@ -3150,19 +3150,7 @@ public class StrokeTool : GLib.Object { } } - /*- foreach (EditPoint ep in interpolated.points) {- if ((ep.flags & EditPoint.SEGMENT_END) != 0) {- deleted.add (new PointSelection (ep, interpolated));- }- }- - foreach (PointSelection ps in deleted) {- PenTool.remove_point_simplify_path (ps);- }- */- - return interpolated; // FIXME: split paths in interpolation?+ return interpolated; } }