The Birdfont Source Code


All Repositories / birdfont.git / commit – RSS feed

Generate outline for new masters from stroked paths

These changes was commited to the Birdfont repository Mon, 16 Nov 2015 16:09:36 +0000.

Contributing

Send patches or pull requests to johan.mattsson.m@gmail.com.
Clone this repository: git clone https://github.com/johanmattssonm/birdfont.git
author Johan Mattsson <johan.mattsson.m@gmail.com>
Mon, 16 Nov 2015 16:09:36 +0000 (17:09 +0100)
committer Johan Mattsson <johan.mattsson.m@gmail.com>
Mon, 16 Nov 2015 16:09:36 +0000 (17:09 +0100)
commit ebfec3aeefa6bac6ad8389899fa01168a53e5cc7
tree 2b90859eefc58a6509e4c4be32071d7f54361c61
parent f99f285b2fa7ede60ea7d2b6f80df1a02ceb6f46
Generate outline for new masters from stroked paths

libbirdfont/EditPointHandle.vala
libbirdfont/Glyph.vala
libbirdfont/GlyphCollection.vala
libbirdfont/OverViewItem.vala
libbirdfont/OverviewTools.vala
libbirdfont/Path.vala
libbirdfont/StrokeTool.vala
--- a/libbirdfont/EditPointHandle.vala +++ b/libbirdfont/EditPointHandle.vala @@ -219,7 +219,7 @@ process_connected_handle (); } - + public void move_to_coordinate_internal (double x, double y) { double a, b, c; @@ -308,7 +308,16 @@ public bool is_line () { return PenTool.is_line (type); } + + public static double average_angle (double angle1, double angle2) { + EditPointHandle handle = new EditPointHandle (new EditPoint (0, 0), 0, 1); + double x = (cos (angle1) + cos (angle2)) / 2; + double y = (sin (angle1) + sin (angle2)) / 2; + handle.move_to_coordinate (x, y); + return handle.angle; + } + } }
--- a/libbirdfont/Glyph.vala +++ b/libbirdfont/Glyph.vala @@ -2444,12 +2444,38 @@ GlyphCanvas.redraw (); } - public void self_interpolate (double weight) { + public Glyph self_interpolate (double weight) { + Glyph g = copy (); + g.fix_curve_orientation (); + g.layers = new Layer (); // remove all paths + foreach (Path p in get_visible_paths ()) { - p.self_interpolate (weight); + bool counter = !p.is_clockwise (); + + g.add_path (p.copy ()); + Path master = p.get_self_interpolated_master (counter); + g.add_path (master); + + g.add_path (p.interpolate_estimated_path (master, weight)); } + + 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; } } }
--- a/libbirdfont/GlyphCollection.vala +++ b/libbirdfont/GlyphCollection.vala @@ -21,10 +21,8 @@ unichar unicode_character; string name; bool unassigned; - public Gee.ArrayList<GlyphMaster> glyph_masters; - - // FIXME: move this somewhere - static int current_master = 0; + public Gee.ArrayList<GlyphMaster> glyph_masters; + int current_master = 0; public GlyphCollection (unichar unicode_character, string name) { this.unicode_character = unicode_character; @@ -66,7 +64,7 @@ add_master (m); return m; } else if (unlikely (i >= glyph_masters.size)) { - warning(@"No master at index $i."); + warning(@"No master at index $i. ($(glyph_masters.size)) in $(name)"); i = glyph_masters.size - 1; } @@ -146,16 +144,28 @@ } if (glyph_masters.size == 1) { - Glyph master1 = get_current ().copy (); - master1.self_interpolate (weight); - return master1; + return get_current ().self_interpolate (weight); } else { warning("Not implemented."); } return get_current (); } - + + public Glyph get_interpolated_fast (double weight) { + if (weight == 0) { // FIXME: compare to master weight + return get_current (); + } + + if (glyph_masters.size == 1) { + return get_current ().self_interpolate_fast (weight); + } else { + warning("Not implemented."); + } + + return get_current (); + } + public void insert_glyph (Glyph g, bool selected_glyph) { get_current_master ().insert_glyph (g, selected_glyph); }
--- a/libbirdfont/OverViewItem.vala +++ b/libbirdfont/OverViewItem.vala @@ -211,7 +211,7 @@ if (gl != null) { font = BirdFont.get_current_font (); - g = ((!) gl).get_interpolated (OverviewTools.current_master_size); + g = ((!) gl).get_interpolated_fast (OverviewTools.current_master_size); c.save (); g.boundaries (out x1, out y1, out x2, out y2);
--- a/libbirdfont/OverviewTools.vala +++ b/libbirdfont/OverviewTools.vala @@ -199,7 +199,6 @@ master.add_glyph(g); glyph_collection.add_master (master); glyph_collection.set_selected_master (master); - print(@"$(glyph_collection.get_name ())\n"); i++; gc = font.get_glyph_collection_indice (i);
--- a/libbirdfont/Path.vala +++ b/libbirdfont/Path.vala @@ -2640,8 +2640,8 @@ EditPoint p = new EditPoint (Glyph.CANVAS_MAX, Glyph.CANVAS_MAX); foreach (EditPoint ep in points) { - d = distance (x, ep.x, y, ep.y); - + d = distance (x, ep.x, y, ep.y); + if (d < min) { min = d; p = ep; @@ -2651,71 +2651,80 @@ return p; } - public void self_interpolate (double weight) { + public Path self_interpolate (double weight, bool counter) { Path master; + Path p = new Path (); if (stroke > 0) { - stroke += 5 * weight * 2; + p = copy (); + p.stroke += 5 * weight * 2; - if (stroke < 0.002) { - stroke = 0.002; + if (p.stroke < 0.002) { + p.stroke = 0.002; } } else { remove_points_on_points (); - master = get_self_interpolated_master (); - interpolate_path (master, weight); + master = get_self_interpolated_master (counter); + p = interpolate_estimated_path (master, weight); recalculate_linear_handles (); - } - } - - Path get_self_interpolated_master () { - Path master = new Path (); - EditPoint ep1, ep2, none; - - none = new EditPoint (); - for (int i = 0; i < points.size; i++) { - ep1 = points.get (i).copy (); - ep2 = ep1.copy (); - - StrokeTool.move_segment (ep1, none, 5); - StrokeTool.move_segment (none, ep2, 5); - - ep1.x = (ep2.x + ep1.x) / 2; - ep1.y = (ep2.y + ep1.y) / 2; - - master.add_point (ep1.copy ()); } - return master; + return p; } - void interpolate_path (Path master, double weight) { + 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; - - if (unlikely (points.size != master.points.size)) { - warning ("Master and path must have the same number of points."); - return; - } - - for (int i = 0; i < points.size; i++) { - ep = points.get (i); - master_point = master.points.get (i); - + double x, y; + + master_point = new EditPoint (); + + for (int i = 0; i < p.points.size; i++) { + ep = p.points.get (i); + + double right_angle = ep.get_right_handle ().angle; + double left_angle = ep.get_left_handle ().angle; + double angle = EditPointHandle.average_angle (right_angle, left_angle); + angle += PI; + angle %= 2 * PI; + + x = ep.x + 5 * cos (angle); + y = ep.y + 5 * sin (angle); + + 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); + ep.x += (master_point.x - ep.x) * weight; ep.y += (master_point.y - ep.y) * weight; + /* h = ep.get_right_handle (); - length = master_point.get_right_handle ().length; - h.length = length * weight + h.length * (1 - weight); + h.length += 5 * weight; h = ep.get_left_handle (); - length = master_point.get_left_handle ().length; - h.length = length * weight + h.length * (1 - weight) ; + h.length += 5 * weight; + */ } + + return p; + } + + public Path get_self_interpolated_master (bool counter) { + return StrokeTool.change_weight (this, counter); } } }
--- a/libbirdfont/StrokeTool.vala +++ b/libbirdfont/StrokeTool.vala @@ -2799,8 +2799,7 @@ return sum > 0; } - public PathList create_stroke (Path original_path, double thickness) { - + public PathList create_stroke (Path original_path, double thickness) { PathList pl; EditPoint p1, p2, p3; EditPoint previous, previous_inside, start, start_inside; @@ -3115,7 +3114,57 @@ return paths; } + + public static Path change_weight_fast (Path path, double weight, bool counter) { + StrokeTool tool = new StrokeTool (); + PathList pl; + + pl = tool.get_stroke_fast (path, fabs(weight)); + + return_val_if_fail (pl.paths.size == 2, new Path ()); + + if (counter == !pl.paths.get (0).is_clockwise ()) { + return pl.paths.get (0); + } + + return pl.paths.get (1); + } + + public static Path change_weight (Path path, bool counter) { + StrokeTool tool = new StrokeTool (); + Path o = path.copy (); + Path interpolated = new Path(); + o.force_direction (Direction.CLOCKWISE); + + PathList pl = tool.get_stroke (o, 5); + Gee.ArrayList<PointSelection> deleted; + + deleted = new Gee.ArrayList<PointSelection> (); + + return_val_if_fail (pl.paths.size > 0, new Path ()); + + foreach (Path sp in pl.paths) { + if (sp.points.size > interpolated.points.size + && counter == !sp.is_clockwise ()) { + interpolated = sp; + } + } + + /* + 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? + } } }