Commit 1fe0b77
Split path before creating stroke
Changed files (3)
modifiedlibbirdfont/Line.valamodifiedlibbirdfont/PenTool.valamodifiedlibbirdfont/StrokeTool.vala
Diff
@@ -16,7 +16,7 @@ using Cairo; namespace BirdFont { -/** Help line */+/** Guide */ public class Line : GLib.Object { public static const bool VERTICAL = true; public static const bool HORIZONTAL = false;@@ -1004,6 +1004,88 @@ public class PenTool : Tool { 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 (); Path? p;@@ -1024,8 +1106,8 @@ public class PenTool : Tool { warning ("No path to join."); return; }+ path = (!) p;- if (!path.is_open ()) { warning ("Path is closed."); return;@@ -1053,56 +1135,19 @@ public class PenTool : Tool { 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 @@ public class PenTool : Tool { 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 ();@@ -79,7 +79,17 @@ public class StrokeTool : Tool { 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 @@ public class StrokeTool : Tool { 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 @@ public class StrokeTool : Tool { } 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 @@ public class StrokeTool : Tool { } parts = remove_intersections (merged, thickness, p);+ parts = merge (parts); foreach (Path sp in parts.paths) { paths.add (sp);@@ -329,7 +340,7 @@ public class StrokeTool : Tool { 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 @@ public class StrokeTool : Tool { /** 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 @@ public class StrokeTool : Tool { 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 @@ public class StrokeTool : Tool { } } + /** @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;@@ -663,6 +669,89 @@ public class StrokeTool : Tool { 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;+ } } }