The Birdfont Source Code


All Repositories / birdfont.git / commit – RSS feed

Stroke

These changes was commited to the Birdfont repository Sun, 26 Apr 2015 18:02:15 +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>
Sun, 26 Apr 2015 18:02:15 +0000 (20:02 +0200)
committer Johan Mattsson <johan.mattsson.m@gmail.com>
Sun, 26 Apr 2015 22:15:08 +0000 (00:15 +0200)
commit 7db41696c6dd6b2e2cb16b2a51b705f3d594e117
tree b069244f853641249a4ae2c6988428728c204e9c
parent 92e89f63534918b84b574eaf2d33df73c4f0f556
Stroke

libbirdfont/DrawingTools.vala
libbirdfont/Path.vala
libbirdfont/StrokeTool.vala
--- a/libbirdfont/DrawingTools.vala +++ b/libbirdfont/DrawingTools.vala @@ -730,23 +730,24 @@ add_stroke.select_action.connect ((self) => { Glyph g = MainWindow.get_current_glyph (); StrokeTool.add_stroke = !StrokeTool.add_stroke; + StrokeTool.stroke_width = object_stroke.get_value (); + add_stroke.selected = StrokeTool.add_stroke; - + + GlyphCanvas.redraw (); + g.store_undo_state (); + if (StrokeTool.add_stroke) { foreach (Path p in g.active_paths) { p.stroke = StrokeTool.stroke_width; } - - StrokeTool.stroke_width = object_stroke.get_value (); - StrokeTool.set_stroke_for_selected_paths (StrokeTool.stroke_width); } else { foreach (Path p in g.active_paths) { p.stroke = 0; - } - } + } + } - add_stroke.selected = StrokeTool.add_stroke; - GlyphCanvas.redraw (); + print (@"select $(StrokeTool.add_stroke)\n"); }); stroke_expander.add_tool (add_stroke); @@ -758,6 +759,7 @@ object_stroke.new_value_action.connect((self) => { Font f; + Glyph g = MainWindow.get_current_glyph (); bool tool = resize_tool.is_selected () || move_tool.is_selected () @@ -766,11 +768,14 @@ || point_tool.is_selected () || foresight_tool.is_selected (); - if (tool && object_stroke.is_selected () && StrokeTool.add_stroke) { - StrokeTool.set_stroke_for_selected_paths (object_stroke.get_value ()); + StrokeTool.stroke_width = object_stroke.get_value (); + + if (tool && StrokeTool.add_stroke) { + foreach (Path p in g.active_paths) { + p.stroke = StrokeTool.stroke_width; + } } - StrokeTool.stroke_width = object_stroke.get_value (); f = BirdFont.get_current_font (); f.settings.set_setting ("stroke_width", object_stroke.get_display_value ()); });
--- a/libbirdfont/Path.vala +++ b/libbirdfont/Path.vala @@ -872,7 +872,6 @@ return !(xmax <= p.xmin || ymax <= p.ymin) || (xmin >= p.xmax || ymin >= p.ymax); } - // FIXME: DELETE? public EditPoint delete_first_point () { EditPoint r; int size;
--- a/libbirdfont/StrokeTool.vala +++ b/libbirdfont/StrokeTool.vala @@ -26,18 +26,6 @@ public static bool stroke_selected = false; public StrokeTool (string tooltip) { - } - - public static void set_stroke_for_selected_paths (double width) { - Glyph g = MainWindow.get_current_glyph (); - - g.store_undo_state (); - - foreach (Path p in g.active_paths) { - p.set_stroke (width); - } - - GlyphCanvas.redraw (); } /** Create strokes for the selected outlines. */ @@ -100,15 +88,17 @@ PathList n, o; Path stroke = path.copy (); + /* if (!stroke.is_clockwise ()) { stroke.force_direction (Direction.CLOCKWISE); } + */ stroke.remove_points_on_points (0.3); // FIXME: flatten (stroke, thickness); - n = get_stroke_outline (stroke, thickness); + // n = get_stroke_outline (stroke, thickness); o = get_overlay (stroke, thickness); foreach (Path p in o.paths) { @@ -116,10 +106,13 @@ ((!) BirdFont.get_current_font ().get_glyph ("c")).add_path (p); } } + //o = merge (o); + /* foreach (Path p in n.paths) { p.remove_points_on_points (0.3); } + */ // o = split_corners (n); // o = get_all_parts (n); @@ -141,12 +134,12 @@ } }*/ - n = merge (n); + //n = merge (n); // FIXME: this needs to be solved. // remove_self_intersecting_corners (n); - n = remove_remaining_corners (n); + // n = remove_remaining_corners (n); // return n; // FIXME: return o; @@ -262,70 +255,6 @@ } } } - } - - public static PathList get_stroke_outline (Path path, double thickness) { - return get_strokes (path, thickness); - } - - public static PathList get_strokes (Path p, double thickness) { - Path counter = new Path (); - Path outline = new Path (); - Path merged = new Path (); - PathList paths = new PathList (); - - if (!p.is_open () && p.is_filled ()) { - outline = create_stroke (p, thickness); - outline.close (); - - outline.update_region_boundaries (); - paths.add (outline); - } else if (!p.is_open () && !p.is_filled ()) { - outline = create_stroke (p, thickness); - counter = create_stroke (p, -1 * thickness); - - if (p.is_clockwise ()) { - outline.force_direction (Direction.CLOCKWISE); - } else { - outline.force_direction (Direction.COUNTER_CLOCKWISE); - } - - if (outline.is_clockwise ()) { - counter.force_direction (Direction.COUNTER_CLOCKWISE); - } else { - counter.force_direction (Direction.CLOCKWISE); - } - - outline.update_region_boundaries (); - paths.add (outline); - - counter.update_region_boundaries (); - paths.add (counter); - } else if (p.is_open ()) { // FIXME: this can create many parts - outline = create_stroke (p, thickness); - counter = create_stroke (p, -1 * thickness); - - if (stroke_selected) {// FIXME: DELETE - ((!) BirdFont.get_current_font ().get_glyph ("b")).add_path (outline.copy ()); - ((!) BirdFont.get_current_font ().get_glyph ("b")).add_path (counter.copy ()); - } - - merged = merge_strokes (p, outline, counter, thickness); - - if (p.is_clockwise ()) { - merged.force_direction (Direction.CLOCKWISE); - } else { - merged.force_direction (Direction.COUNTER_CLOCKWISE); - } - - merged.update_region_boundaries (); - paths.add (merged); - } else { - warning ("Can not create stroke."); - paths.add (p); - } - - return paths; } /** Create one stroke from the outline and counter stroke and close the @@ -335,21 +264,29 @@ * @param stroke for the outline of path * @param stroke for the counter path */ - static Path merge_strokes (Path path, Path stroke, Path counter, double thickness) { + static Path merge_strokes (Path path, Path stroke, Path counter) { Path merged; EditPoint last_counter, first; merged = stroke.copy (); counter.reverse (); + + counter.reverse (); + merged.reverse (); last_counter = new EditPoint (); first = new EditPoint (); if (path.is_open ()) { - merged.delete_last_point (); - counter.delete_first_point (); - merged.delete_last_point (); - counter.delete_first_point (); + counter.delete_last_point (); + counter.delete_last_point (); + merged.delete_first_point (); + merged.delete_first_point (); + + counter.delete_last_point (); + counter.delete_last_point (); + merged.delete_first_point (); + merged.delete_first_point (); } merged.append_path (counter); @@ -361,6 +298,7 @@ if (path.is_open ()) { first = merged.get_first_point (); last_counter = merged.get_last_point (); + first.color = Color.pink (); first.get_left_handle ().convert_to_line (); first.recalculate_linear_handles (); @@ -562,7 +500,7 @@ EditPointHandle previous_handle; EditPointHandle next_handle; EditPoint cutoff1, cutoff2; - double adjusted_stroke = stroke_width * 0.999999; + double adjusted_stroke = (stroke_width * 0.999999) / 2.0; previous_handle = previous.get_left_handle (); next_handle = next.get_right_handle (); @@ -580,6 +518,7 @@ distance = Path.distance_to_point (corner, original); ratio = 1.5 * fabs (adjusted_stroke) / distance; + /* if (ratio < 0) { return; } @@ -592,11 +531,13 @@ if (Path.distance_to_point (previous, next) < fabs (0.2 * stroke_width)) { return; } - + */ + /* if (distance < stroke_width) { previous.flags |= EditPoint.NEW_CORNER; next.flags |= EditPoint.NEW_CORNER; } else { + */ if (ratio > 1) { stroked.add_point (corner); } else { @@ -630,7 +571,7 @@ next.flags |= EditPoint.NEW_CORNER; } } - } + //} } static PathList get_parts (Path path) { @@ -1466,7 +1407,7 @@ bool inside; foreach (Path p in pl.paths) { - inside = false; + inside = true; if (p.points.size > 1 && p != path @@ -1475,8 +1416,8 @@ // FIXME: all points can be corners in counter paths foreach (EditPoint ep in path.points) { - if (is_inside (ep, p)) { - inside = true; + if (!is_inside (ep, p)) { + inside = false; } } @@ -2104,115 +2045,165 @@ public static PathList get_overlay (Path path, double thickness) { PathList pl = new PathList (); Path np; - EditPoint p1, p2; + EditPoint p1, p2, p3; EditPoint last1, last2; + EditPoint previous, previous_inside, start, original_start; + + Path side1, side2; double x, y, x2, y2, x3, y3, next_x, next_y, step, prev_x, prev_y; double previus_x, previus_y, previus_x2, previus_y2; double previus_middle_x, previus_middle_y; - int size = path.is_open () ? path.points.size - 1 : path.points.size; - bool flat; + int size = path.points.size; + bool flat, f, f_next; - for (int i = 0; i < size; i++) { - p1 = path.points.get (i); + side1 = new Path (); + side2 = new Path (); + + return_val_if_fail (path.points.size > 0, pl); + + previous = new EditPoint (); + previous_inside = new EditPoint (); + + int i; + + if (path.is_open ()) { + get_segment (thickness, 0, 0.001, p2, p3, out start); + add_corner (side1, previous, start, p2.copy (), thickness); + + get_segment (-thickness, 0, 0.001, p2, p3, out start); + add_corner (side2, previous_inside, start, p2.copy (), thickness); + } + + for (i = 0; i < size; i++) { + p1 = path.points.get (i % path.points.size); p2 = path.points.get ((i + 1) % path.points.size); + p3 = path.points.get ((i + 2) % path.points.size); - previus_x = p1.x; - previus_y = p1.y; - previus_middle_x = p1.x; - previus_middle_y = p1.y; - - int steps = 4; - double step_size = 1.0 / steps; - - EditPoint corner1, corner2, corner3, corner4, corner5; + double step_size = 0.013; + EditPoint corner1, corner1_inside; corner1 = new EditPoint (); - corner2 = new EditPoint (); - corner3 = new EditPoint (); - corner4 = new EditPoint (); - corner5 = new EditPoint (); - last1 = new EditPoint (); - last2 = new EditPoint (); - - Path last = new Path (); - for (int j = 0; j < steps; j++) { - step = j * step_size; + step = 0; + while (step < 1 - step_size) { Path.get_point_for_step (p1, p2, step, out x, out y); Path.get_point_for_step (p1, p2, step + step_size, out x2, out y2); Path.get_point_for_step (p1, p2, step + 2 * step_size, out x3, out y3); - EditPoint c1; - EditPoint c2; + flat = is_flat (x, y, x2, y2, x3, y3, 0.01); // FIXME: stroke_width - Path overlay; + Path.get_point_for_step (p1, p2, step, out x, out y); + Path.get_point_for_step (p1, p2, step + step_size / 2, out x2, out y2); + Path.get_point_for_step (p1, p2, step + 2 * step_size / 2, out x3, out y3); - flat = is_flat (x, y, x2, x2, x3, y3, 0.05 * stroke_width); - if (!flat && steps < 75) { - j--; - steps += 1; - step_size = 1.0 / steps; + f_next = is_flat (x, y, x2, y2, x3, y3, 0.01); // FIXME: stroke_width + + if (!flat && !f_next && step_size > 0.013) { + print (@"Not flat. $step_size\n"); + step_size /= 2; continue; - } - /* - flat = is_flat (x, y, x2, x2, x3, y3, 0.1 * stroke_width); - if (!flat && steps > 4) { - steps -= 1; - step_size = 1.0 / steps; + } + + if (flat && f_next && step_size < 0.5) { + print (@"Flat. $step_size\n"); + step_size *= 2; continue; - } - */ - overlay = new Path (); - - corner1 = new EditPoint (previus_x, previus_y, PointType.LINE_CUBIC); - corner2 = new EditPoint (x, y, PointType.LINE_CUBIC); - corner3 = new EditPoint (x2, y2, PointType.LINE_CUBIC); - corner4 = new EditPoint (previus_x, previus_y, PointType.LINE_CUBIC); - - overlay.add_point (corner1); - overlay.add_point (corner2); - - overlay.add_point (corner3); - overlay.add_point (corner4); - - c1 = corner1; - c2 = corner2; - - overlay.close (); - overlay.recalculate_linear_handles (); - - move_segment (corner1, corner2, thickness); - - if (j > 0) { - pl.add (overlay); - } - - np = new Path (); - np.add_point (last1); - np.add_point (last2); - np.add_point (corner1.copy ()); - np.add_point (corner2.copy ()); - np.add_point (corner3.copy ()); - np.add_point (corner4.copy ()); - - if (j > 0) { - pl.add (np); } - last1 = corner1.copy (); - last2 = corner1.copy (); + get_segment (thickness, step, step_size, p1, p2, out corner1); + get_segment (-thickness, step, step_size, p1, p2, out corner1_inside); + side1.add_point (corner1.copy ()); + side2.add_point (corner1_inside.copy ()); + previous = corner1; + previous_inside = corner1_inside; - previus_x = x; - previus_y = y; - previus_x2 = x2; - previus_y2 = y2; + step += step_size; } + + get_segment (thickness, 1 - step_size, step_size, p1, p2, out corner1); + get_segment (-thickness, 1 - step_size, step_size, p1, p2, out corner1_inside); + side1.add_point (corner1.copy ()); + side2.add_point (corner1_inside.copy ()); + previous = corner1; + previous_inside = corner1_inside; + + get_segment (thickness, 0, 0.001, p2, p3, out start); + add_corner (side1, previous, start, p2.copy (), thickness); + + get_segment (-thickness, 0, 0.001, p2, p3, out start); + add_corner (side2, previous_inside, start, p2.copy (), thickness); } + + side1.recalculate_linear_handles (); + side2.recalculate_linear_handles (); + + side2.reverse (); + + pl = merge_stroke_parts (path, side1, side2); return pl; + } + + public static void get_segment (double stroke_thickness, double step, double step_size, + EditPoint p1, EditPoint p2, out EditPoint ep1) { + + double thickness = stroke_thickness / 2; + Path overlay; + double x, y, x2, y2, x3, y3; + EditPoint corner1, corner2, corner3; + + Path.get_point_for_step (p1, p2, step, out x, out y); + Path.get_point_for_step (p1, p2, step + step_size, out x2, out y2); + Path.get_point_for_step (p1, p2, step + 2 * step_size, out x3, out y3); + + overlay = new Path (); + + corner1 = new EditPoint (x, y, PointType.LINE_CUBIC); + corner2 = new EditPoint (x2, y2, PointType.LINE_CUBIC); + corner3 = new EditPoint (x3, y3, PointType.LINE_CUBIC); + + overlay.add_point (corner1); + overlay.add_point (corner2); + overlay.add_point (corner3); + + overlay.close (); + overlay.recalculate_linear_handles (); + + move_segment (corner1, corner2, thickness); + + ep1 = corner2; + } + + public static PathList merge_stroke_parts (Path p, Path side1, Path side2) { + Path merged = new Path (); + PathList paths = new PathList (); + + if (!p.is_open () && p.is_filled ()) { + side1.close (); + side1.update_region_boundaries (); + paths.add (side1); + } else if (!p.is_open () && !p.is_filled ()) { + side1.update_region_boundaries (); + paths.add (side1); + side2.update_region_boundaries (); + paths.add (side2); + side1.close (); + side2.close (); + } else if (p.is_open ()) { + side2.reverse (); + merged = merge_strokes (p, side1, side2); + merged.close (); + merged.update_region_boundaries (); + paths.add (merged); + } else { + warning ("Can not create stroke."); + paths.add (p); + } + + return paths; } } }