The Birdfont Source Code


All Repositories / birdfont.git / commitdiff – RSS feed

Split path before creating stroke

These changes was commited to the Birdfont repository Fri, 03 Apr 2015 06:51:37 +0000.

Contributing

Send patches or pull requests to johan.mattsson.m@gmail.com.
Clone this repository: git clone https://github.com/johanmattssonm/birdfont.git
[Fri, 03 Apr 2015 06:51:37 +0000]

Updated Files

libbirdfont/Line.vala
libbirdfont/PenTool.vala
libbirdfont/StrokeTool.vala
--- a/libbirdfont/Line.vala +++ b/libbirdfont/Line.vala @@ -16,7 +16,7 @@ namespace BirdFont { - /** Help line */ + /** Guide */ public class Line : GLib.Object { public static const bool VERTICAL = true; public static const bool HORIZONTAL = false;
--- a/libbirdfont/PenTool.vala +++ b/libbirdfont/PenTool.vala @@ -1003,6 +1003,88 @@ return m; } + + public static Path merge_open_paths (Path path1, Path path2) { + Path union, merge; + EditPoint first_point; + + return_if_fail (path1.points.size > 1); + return_if_fail (path2.points.size > 1); + + union = path1.copy (); + merge = path2.copy (); + + merge.points.get (0).set_tie_handle (false); + merge.points.get (0).set_reflective_handles (false); + + merge.points.get (merge.points.size - 1).set_tie_handle (false); + merge.points.get (merge.points.size - 1).set_reflective_handles (false); + + union.points.get (union.points.size - 1).set_tie_handle (false); + union.points.get (union.points.size - 1).set_reflective_handles (false); + + union.points.get (0).set_tie_handle (false); + union.points.get (0).set_reflective_handles (false); + + first_point = merge.get_first_point (); + + if (union.get_last_point ().get_left_handle ().is_curve ()) { + first_point.get_left_handle ().convert_to_curve (); + } else { + first_point.get_left_handle ().convert_to_line (); + } + + first_point.get_left_handle ().move_to_coordinate_internal ( + union.get_last_point ().get_left_handle ().x, + union.get_last_point ().get_left_handle ().y); + + union.delete_last_point (); + + union.append_path (merge); + + return union; + } + + public static void close_path (Path path) { + Path? p; + EditPoint first_point; + bool last_segment_is_line; + bool first_segment_is_line; + + return_if_fail (path.points.size > 1); + + last_segment_is_line = path.get_last_point ().get_left_handle ().is_line (); + first_segment_is_line = path.get_first_point ().get_right_handle ().is_line (); + + // TODO: set point type + path.points.get (0).left_handle.move_to_coordinate ( + path.points.get (path.points.size - 1).left_handle.x, + path.points.get (path.points.size - 1).left_handle.y); + + path.points.get (0).left_handle.type = + path.points.get (path.points.size - 1).left_handle.type; + + path.points.get (0).recalculate_linear_handles (); + path.points.get (path.points.size - 1).recalculate_linear_handles (); + + // force the connected handle to move + path.points.get (0).set_position ( + path.points.get (0).x, path.points.get (0).y); + + path.points.remove_at (path.points.size - 1); + + path.close (); + + if (last_segment_is_line) { + path.get_first_point ().get_left_handle ().convert_to_line (); + path.get_first_point ().recalculate_linear_handles (); + } + + if (first_segment_is_line) { + path.get_first_point ().get_right_handle ().convert_to_line (); + path.get_first_point ().recalculate_linear_handles (); + } + } private static void join_paths (double x, double y) { Glyph glyph = MainWindow.get_current_glyph (); @@ -1024,8 +1106,8 @@ warning ("No path to join."); return; } + path = (!) p; - if (!path.is_open ()) { warning ("Path is closed."); return; @@ -1053,56 +1135,19 @@ if (is_endpoint ((!) active_edit_point) && is_close_to_point (path.points.get (0), px, py)) { - last_segment_is_line = path.get_last_point ().get_left_handle ().is_line (); - first_segment_is_line = path.get_first_point ().get_right_handle ().is_line (); - - // TODO: set point type - path.points.get (0).left_handle.move_to_coordinate ( - path.points.get (path.points.size - 1).left_handle.x, - path.points.get (path.points.size - 1).left_handle.y); - - path.points.get (0).left_handle.type = - path.points.get (path.points.size - 1).left_handle.type; - - path.points.get (0).recalculate_linear_handles (); - path.points.get (path.points.size - 1).recalculate_linear_handles (); - - // force the connected handle to move - path.points.get (0).set_position ( - path.points.get (0).x, path.points.get (0).y); - - path.points.remove_at (path.points.size - 1); - - path.close (); + close_path (path); glyph.close_path (); - - if (last_segment_is_line) { - path.get_first_point ().get_left_handle ().convert_to_line (); - path.get_first_point ().recalculate_linear_handles (); - } - - if (first_segment_is_line) { - path.get_first_point ().get_right_handle ().convert_to_line (); - path.get_first_point ().recalculate_linear_handles (); - } + force_direction (); - force_direction (); - if (direction_changed) { path.reverse (); update_selection (); } remove_all_selected_points (); - return; } - union = new Path (); - foreach (EditPoint ep in path.points) { - union.add_point (ep.copy ()); - } - foreach (Path merge in glyph.path_list) { // don't join path with itself here if (path == merge) { @@ -1123,35 +1168,9 @@ return_if_fail (merge.points.size > 0); if (is_close_to_point (merge.points.get (0), px, py)) { - merge.points.get (0).set_tie_handle (false); - merge.points.get (0).set_reflective_handles (false); - - merge.points.get (merge.points.size - 1).set_tie_handle (false); - merge.points.get (merge.points.size - 1).set_reflective_handles (false); - - path.points.get (path.points.size - 1).set_tie_handle (false); - path.points.get (path.points.size - 1).set_reflective_handles (false); + union = merge_open_paths (path, merge); - path.points.get (0).set_tie_handle (false); - path.points.get (0).set_reflective_handles (false); - - second_path = merge.copy (); - - first_point = second_path.get_first_point (); - - if (union.get_last_point ().get_left_handle ().is_curve ()) { - first_point.get_left_handle ().convert_to_curve (); - } else { - first_point.get_left_handle ().convert_to_line (); - } - - first_point.get_left_handle ().move_to_coordinate_internal (union.get_last_point ().get_left_handle ().x, union.get_last_point ().get_left_handle ().y); - - union.delete_last_point (); - - union.append_path (second_path); glyph.add_path (union); - glyph.delete_path (path); glyph.delete_path (merge); glyph.clear_active_paths ();
--- a/libbirdfont/StrokeTool.vala +++ b/libbirdfont/StrokeTool.vala @@ -79,7 +79,17 @@ return pl; } - public static PathList get_stroke_outline (Path p, double thickness) { + public static PathList get_stroke_outline (Path path, double thickness) { + PathList pl = new PathList (); + + foreach (Path p in get_parts (path).paths) { + pl.append (get_strokes (p, thickness)); + } + + return pl; + } + + public static PathList get_strokes (Path p, double thickness) { Path counter, outline; Path merged; PathList paths = new PathList (); @@ -90,7 +100,8 @@ outline.close (); parts = remove_intersections (outline, thickness, p); - + parts = merge (parts); + foreach (Path sp in parts.paths) { paths.add (sp); sp.update_region_boundaries (); @@ -112,19 +123,18 @@ } parts = remove_intersections (outline, thickness, p); - foreach (Path sp in parts.paths) { paths.add (sp); sp.update_region_boundaries (); } - - parts = remove_intersections (counter, thickness, p); + parts = remove_intersections (counter, thickness, p); foreach (Path sp in parts.paths) { paths.add (sp); sp.update_region_boundaries (); } - } else if (p.is_open ()) { + + } else if (p.is_open ()) { // FIXME: this can create many parts outline = create_stroke (p, thickness); counter = create_stroke (p, -1 * thickness); merged = merge_strokes (p, outline, counter, thickness); @@ -136,6 +146,7 @@ } parts = remove_intersections (merged, thickness, p); + parts = merge (parts); foreach (Path sp in parts.paths) { paths.add (sp); @@ -329,7 +340,7 @@ static PathList remove_intersections (Path path, double thickness, Path original) { PathList parts; - + parts = get_parts (path); delete_intersection_parts (original, parts, thickness); @@ -370,7 +381,7 @@ /** Split one path at intersection points in two parts. */ static PathList split (Path path) { PathList pl; - int i = 0; + int i; if (!has_intersection_points (path)) { add_self_intersection_points (path); @@ -378,13 +389,7 @@ warning ("points already created."); } - foreach (EditPoint p in path.points) { - if ((p.flags & EditPoint.INTERSECTION) > 0) { - p.deleted = true; - i++; - // FIXME: delete p.color = new Color (1, 1, 0, 1); - } - } + i = mark_intersection_as_deleted (path); if (!(i == 0 || i == 2)) { warning (@"Split should only create two parts, $i points will be deleted."); @@ -641,6 +646,7 @@ } } + /** @return true if the part is inside of the stroke of the path */ static bool is_stroke (Path original, Path part, double stroke_width) { double stroke_size = fabs (stroke_width); bool stroke = false; @@ -662,8 +668,91 @@ }, 12); return stroke; + } + + static PathList merge (PathList pl) { + Path merged; + + foreach (Path p1 in pl.paths) { + foreach (Path p2 in pl.paths) { + if (merge_path (p1, p2, out merged)) { + //pl.paths.remove (p1); + //pl.paths.remove (p2); + pl.add (merged); + return pl; + } + } + } + + return pl; + } + + static int mark_intersection_as_deleted (Path path) { + int i = 0; + + foreach (EditPoint p in path.points) { + if ((p.flags & EditPoint.INTERSECTION) > 0) { + p.deleted = true; + i++; + // FIXME: delete p.color = new Color (1, 1, 0, 1); + } + } + + return i; + } + + /** @return true if the two paths can be merged. */ + static bool merge_path (Path path1, Path path2, out Path merged) { + PathList pl1, pl2; + Path p1, p2; + int i; + + merged = new Path (); + + if (add_intersection_points (path1, path2)) { + i = mark_intersection_as_deleted (path1); + return_if_fail (i == 1); + + i = mark_intersection_as_deleted (path2); + return_if_fail (i == 1); + + pl1 = get_remaining_points (path1.copy ()); + pl2 = get_remaining_points (path2.copy ()); + + return_if_fail (pl1.paths.size == 1); + return_if_fail (pl2.paths.size == 1); + + p1 = pl1.paths.get (0); + p2 = pl2.paths.get (0); + + merged = PenTool.merge_open_paths (p1, p2); + + return true; + } + + return false; + } + + static bool add_intersection_points (Path path1, Path path2) { + bool intersection = false; + + path1.all_segments ((ep1, ep2) => { + double ix, iy; + EditPoint p1, p2; + + if (segment_intersects (path2, ep1, ep2, out ix, out iy, out p1, out p2)) { + add_intersection (path1, ep1, ep2, ix, iy); + add_intersection (path2, p1, p2, ix, iy); + intersection = true; + return false; + } + + return true; + }); + + return intersection; } } }