The Birdfont Source Code
Round line cap
These changes was commited to the Birdfont repository Mon, 11 May 2015 21:16:49 +0000.
Contributing
Send patches or pull requests to johan.mattsson.m@gmail.com.
Clone this repository: git clone https://github.com/johanmattssonm/birdfont.git
Round line cap
13 files changed:
--- a/libbirdfont/BezierTool.vala
+++ b/libbirdfont/BezierTool.vala
@@ -311,7 +311,7 @@
if (state == MOVE_POINT && current_path.points.size > 0) {
current_path.delete_last_point ();
current_path.reset_stroke ();
- current_path.get_stroke (); // cache better stroke
+ current_path.create_full_stroke (); // cache better stroke
}
state = NONE;
--- a/libbirdfont/Color.vala
+++ b/libbirdfont/Color.vala
@@ -47,10 +47,26 @@
return new Color (222.0 / 255, 203.0 / 255, 43 / 255.0, 1);
}
+ public static Color brown () {
+ return new Color (160.0 / 255, 90.0 / 255, 44.0 / 255, 1);
+ }
+
public static Color pink () {
return new Color (247.0 / 255, 27.0 / 255, 113 / 255.0, 1);
+ }
+
+ public static Color white () {
+ return new Color (1, 1, 1, 1);
+ }
+
+ public static Color grey () {
+ return new Color (0.5, 0.5, 0.5, 1);
+ }
+
+ public static Color magenta () {
+ return new Color (103.0 / 255, 33.0 / 255, 120.0 / 255, 1);
}
}
}
--- a/libbirdfont/DrawingTools.vala
+++ b/libbirdfont/DrawingTools.vala
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012, 2013, 2014 Johan Mattsson
+ Copyright (C) 2012 2013 2014 2015 Johan Mattsson
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
@@ -850,7 +850,41 @@
outline.set_selected (false);
});
stroke_expander.add_tool (outline);
-
+
+ // set line cap
+ Tool line_cap_round = new Tool ("line_cap_round", t_("Round line cap"));
+ line_cap_round.select_action.connect ((self) => {
+ Glyph g;
+
+ g = MainWindow.get_current_glyph ();
+ g.store_undo_state ();
+
+ foreach (Path p in g.active_paths) {
+ p.line_cap = LineCap.ROUND;
+ p.reset_stroke ();
+ }
+
+ GlyphCanvas.redraw ();
+ });
+ stroke_expander.add_tool (line_cap_round);
+
+ Tool line_cap_square = new Tool ("line_cap_square", t_("Square line cap"));
+ line_cap_square.select_action.connect ((self) => {
+ Glyph g;
+
+ g = MainWindow.get_current_glyph ();
+ g.store_undo_state ();
+
+ foreach (Path p in g.active_paths) {
+ p.line_cap = LineCap.SQUARE;
+ p.reset_stroke ();
+ }
+
+ GlyphCanvas.redraw ();
+ });
+ stroke_expander.add_tool (line_cap_square);
+
+ // tests
if (BirdFont.has_argument ("--test")) {
Tool test_case = new Tool ("test_case");
test_case.select_action.connect((self) => {
--- a/libbirdfont/Glyph.vala
+++ b/libbirdfont/Glyph.vala
@@ -1238,7 +1238,7 @@
p.convert_path_ending_to_line ();
}
- p.get_stroke (); // cache stroke
+ p.create_full_stroke (); // cache stroke
}
open = false;
--- a/libbirdfont/MoveTool.vala
+++ b/libbirdfont/MoveTool.vala
@@ -156,7 +156,7 @@
DrawingTools.resize_tool.signal_objects_rotated ();
foreach (Path p in glyph.active_paths) {
- p.get_stroke ();
+ p.create_full_stroke ();
}
} else {
objects_deselected ();
--- a/libbirdfont/Path.vala
+++ b/libbirdfont/Path.vala
@@ -48,6 +48,7 @@
/** Stroke width */
public double stroke = 0;
+ public LineCap line_cap = LineCap.BUTT;
PathList? full_stroke = null;
PathList? fast_stroke = null;
@@ -756,6 +757,7 @@
new_path.edit = edit;
new_path.open = open;
new_path.stroke = stroke;
+ new_path.line_cap = line_cap;
new_path.skew = skew;
new_path.fill = fill;
new_path.direction_is_set = direction_is_set;
@@ -2320,7 +2322,9 @@
}
public void create_full_stroke () {
- full_stroke = StrokeTool.get_stroke (this, stroke);
+ if (stroke > 0) {
+ full_stroke = StrokeTool.get_stroke (this, stroke);
+ }
}
public PathList get_stroke () {
--- a/libbirdfont/PenTool.vala
+++ b/libbirdfont/PenTool.vala
@@ -188,7 +188,7 @@
p.get_last_point ().set_reflective_handles (false);
}
- p.get_stroke (); // cache good stroke
+ p.create_full_stroke (); // cache good stroke
}
});
--- a/libbirdfont/ResizeTool.vala
+++ b/libbirdfont/ResizeTool.vala
@@ -108,7 +108,7 @@
GlyphCanvas.redraw ();
foreach (Path p in MainWindow.get_current_glyph ().active_paths) {
- p.get_stroke ();
+ p.create_full_stroke ();
}
});
--- a/libbirdfont/StrokeTool.vala
+++ b/libbirdfont/StrokeTool.vala
@@ -16,6 +16,12 @@
using Math;
namespace BirdFont {
+
+ public enum LineCap {
+ BUTT,
+ SQUARE,
+ ROUND
+ }
public class StrokeTool : Tool {
@@ -283,26 +289,123 @@
return false;
}
- static void add_line_cap (Path path, Path stroke,
- EditPointHandle last_handle,
- EditPoint start, EditPoint end) {
+ static void add_line_cap (Path path, Path stroke1, Path stroke2, bool last_cap) {
+ if (path.line_cap == LineCap.SQUARE) {
+ add_square_cap (path, stroke1, stroke2, last_cap);
+ } else if (path.line_cap == LineCap.ROUND) {
+ add_round_cap (path, stroke1, stroke2, last_cap);
+ }
+ }
+
+ static void add_round_cap (Path path, Path stroke1, Path stroke2, bool last_cap) {
+ double px, py;
+ double step, start_angle, stop_angle;
+ double radius;
+ EditPoint n, nstart, nend;
+ Path cap = new Path ();
- EditPoint n;
- double stroke_width = path.stroke / 2;
+ EditPoint start, end;
+ EditPointHandle last_handle;
+ EditPoint first, last;
- double y = sin (last_handle.angle - PI) * stroke_width;
- double x = cos (last_handle.angle - PI) * stroke_width;
+ stroke1.remove_points_on_points ();
+ stroke2.remove_points_on_points ();
- n = stroke.add (start.x + x, start.y + y);
- n.type = start.type;
- n.get_right_handle ().type = start.type;
- n.get_left_handle ().type = start.type;
+ last_handle = path.get_first_point ().get_right_handle ();
+ start = stroke1.get_last_point ();
+ end = stroke2.get_first_point ();
+
+ start_angle = last_handle.angle + PI / 2;
+ stop_angle = start_angle + PI;
+
+ nstart = cap.add (start.x, start.y);
+ radius = Path.distance_to_point (start, end) / 2;
+ step = PI / 5;
+
+ for (int j = 0; j < 5; j++) {
+ double angle = start_angle + step * j;
+ px = radius * cos (angle) + last_handle.parent.x;
+ py = radius * sin (angle) + last_handle.parent.y;
+ n = cap.add (px, py);
+
+ n.type = PointType.LINE_CUBIC;
+ n.get_right_handle ().type = PointType.LINE_CUBIC;
+ n.get_left_handle ().type = PointType.LINE_CUBIC;
+ }
+
+ nend = cap.add (end.x, end.y);
+
+ for (int i = 0; i < cap.points.size; i++) {
+ cap.points.get (i).recalculate_linear_handles ();
+ }
+
+ int size = cap.points.size;
+
+ for (int i = 1; i < size; i++) {
+ n = cap.points.get (i);
+ n.convert_to_curve ();
+ n.set_tie_handle (true);
+ n.process_tied_handle ();
+ }
+
+ int f = stroke1.points.size - 1;
+
+ for (int i = 2; i < cap.points.size - 1; i++) {
+ n = cap.points.get (i).copy ();
+ stroke1.add_point (n);
+ }
+
+ return_if_fail (0 < f < stroke1.points.size);
+
+ first = stroke1.points.get (f);
+ stroke1.add_point (stroke2.get_first_point ());
+
+ last = stroke1.get_last_point ();
+
+ double a;
+ double l;
+
+ return_if_fail (cap.points.size > 1);
+
+ a = (first.get_left_handle ().angle + PI) % (2 * PI);
+ l = cap.points.get (1).get_right_handle ().length;
+
+ first.get_right_handle ().convert_to_curve ();
+ first.get_right_handle ().angle = a;
+ first.get_right_handle ().length = l;
+
+ a = (first.get_left_handle ().angle + PI) % (2 * PI);
+
+ last.get_left_handle ().convert_to_curve ();
+ last.get_left_handle ().angle = a;
+ last.get_left_handle ().length = l;
+ }
+
+ static void add_square_cap (Path path, Path stroke1, Path stroke2, bool last_cap) {
+ EditPointHandle last_handle;
+ EditPoint start;
+ EditPoint end;
+ EditPoint n;
+ double x, y;
+ double stroke_width = path.stroke / 2;
+
+ last_handle = path.get_first_point ().get_right_handle ();
+ start = stroke1.get_last_point ();
+ end = stroke2.get_first_point ();
+
+ y = sin (last_handle.angle - PI) * stroke_width;
+ x = cos (last_handle.angle - PI) * stroke_width;
+
+ n = stroke1.add (start.x + x, start.y + y);
+ n.type = PointType.CUBIC;
+ n.get_right_handle ().type = PointType.CUBIC;
+ n.get_left_handle ().type = PointType.CUBIC;
n.convert_to_line ();
- n = stroke.add (end.x + x, end.y + y);
- n.type = start.type;
- n.get_right_handle ().type = start.type;
- n.get_left_handle ().type = start.type;
+ n = stroke1.add (end.x + x, end.y + y);
+ n.type = PointType.CUBIC;
+ n.get_right_handle ().type = PointType.CUBIC;
+ n.get_left_handle ().type = PointType.CUBIC;
n.convert_to_line ();
}
@@ -317,28 +420,26 @@
Path merged;
EditPoint last_counter, first;
-
+
merged = stroke.copy ();
- counter.reverse ();
-
- counter.reverse ();
merged.reverse ();
last_counter = new EditPoint ();
first = new EditPoint ();
- add_line_cap (path, merged, path.get_first_point ().get_right_handle (),
- merged.get_last_point (), counter.get_first_point ());
+ add_line_cap (path, merged, counter, true);
+ path.reverse ();
+
+ add_line_cap (path, counter, merged, true);
+ path.reverse ();
merged.append_path (counter);
-
- add_line_cap (path, merged, path.get_last_point ().get_left_handle (),
- merged.get_last_point (), merged.get_first_point ());
merged.close ();
merged.create_list ();
merged.recalculate_linear_handles ();
-
+ /*
+ // BUTT CAP
if (path.is_open ()) {
first = merged.get_first_point ();
last_counter = merged.get_last_point ();
@@ -349,7 +450,7 @@
last_counter.get_right_handle ().convert_to_line ();
last_counter.recalculate_linear_handles ();
}
-
+ */
return merged;
}
@@ -2094,17 +2195,17 @@
previous_inside.flags |= EditPoint.CURVE;
side1.add_point (previous);
- side2.add_point (previous_inside);
+ side2.add_point (previous_inside);
}
}
if (!fast) {
side1.remove_points_on_points ();
side2.remove_points_on_points ();
-
+
convert_to_curve (side1);
convert_to_curve (side2);
-
+
side2.reverse ();
pl = merge_stroke_parts (path, side1, side2);
}
--- a/libbirdfont/SvgArc.vala
+++ b/libbirdfont/SvgArc.vala
@@ -158,6 +158,8 @@
for (double a = 0; a < fabs (angleExtent); a += step) {
theta = PI - angleStart - angleExtent + s * a;
+
+ return_if_fail (0 <= bi < bezier_points.length);
bezier_points[bi].type = 'S';
bezier_points[bi].svg_type = 'a';
--- a/libbirdfont/SvgParser.vala
+++ b/libbirdfont/SvgParser.vala
@@ -1195,16 +1195,8 @@
return path_list;
}
- /* //FIXME: DELETE
- if (bezier_points[bi - 1].type != 'z') {
- bezier_points[bi].type = 'z';
- bezier_points[bi].svg_type = 'z';
- bi++;
- }
- */
+ move_and_resize (bezier_points, bi, svg_glyph, units, glyph);
- move_and_resize (bezier_points, bi, svg_glyph, units, glyph);
-
if (format == SvgFormat.ILLUSTRATOR) {
path_list = create_paths_illustrator (bezier_points, bi);
} else {
@@ -1578,7 +1570,6 @@
}
if (path.points.size > 0) {
- warning ("Open path.");
path_list.add (path);
}
--- a/libbirdfont/TrackTool.vala
+++ b/libbirdfont/TrackTool.vala
@@ -122,7 +122,7 @@
drawing = true;
foreach (Path path in glyph.active_paths) {
- path.get_stroke (); // cache merged stroke parts
+ path.create_full_stroke (); // cache merged stroke parts
}
}
});