The Birdfont Source Code


All Repositories / birdfont.git / commit – RSS feed

Select SVG objects

These changes was commited to the Birdfont repository Fri, 15 Jul 2016 13:47:12 +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>
Fri, 15 Jul 2016 13:47:12 +0000 (15:47 +0200)
committer Johan Mattsson <johan.mattsson.m@gmail.com>
Fri, 15 Jul 2016 13:47:12 +0000 (15:47 +0200)
commit 7bf31d87cebbf64827bce0e543a12dcd62f0a9f9
tree da23ca1de3e61e39a62d777b2add42c0ff5696aa
parent 33b640bfddc1dedfb34352dd22fb278d002e88d0
Select SVG objects

libsvgbird/Circle.vala
libsvgbird/Ellipse.vala
libsvgbird/Object.vala
libsvgbird/Rectangle.vala
libsvgbird/SvgDrawing.vala
libsvgbird/SvgPath.vala
--- a/libsvgbird/Circle.vala +++ b/libsvgbird/Circle.vala @@ -26,7 +26,9 @@ } public override bool is_over (double x, double y) { - return false; + double dx = x - cx; + double dy = y - cy; + return Math.sqrt (dx * dx + dy * dy) <= r; } public override void draw_outline (Context cr) {
--- a/libsvgbird/Ellipse.vala +++ b/libsvgbird/Ellipse.vala @@ -28,7 +28,9 @@ } public override bool is_over (double x, double y) { - return false; + double point_x = x - cx; + double point_y = y - cy; + return (point_x * point_x) / (rx * rx) + (point_y * point_y) / (ry * ry) <= 1; } public override void draw_outline (Context cr) {
--- a/libsvgbird/Object.vala +++ b/libsvgbird/Object.vala @@ -93,7 +93,10 @@ public Object.create_copy (Object o) { } - public abstract bool is_over (double x, double y); + public virtual bool is_over (double x, double y) { + return left <= x <= right && top <= y <= bottom; + } + public abstract void draw_outline (Context cr); public abstract Object copy (); @@ -126,6 +129,10 @@ public virtual string to_string () { return "Object"; + } + + public bool is_over_boundaries (double x, double y) { + return top <= y <= bottom && left <= x <= right; } public void paint (Context cr) { @@ -213,6 +220,8 @@ public virtual bool update_boundaries (Context context) { double x0, y0, x1, y1; bool has_stroke = style.has_stroke (); + + apply_transform (context); if (has_stroke) { context.set_line_width (style.stroke_width); @@ -223,15 +232,18 @@ draw_outline (context); context.save (); - - context.set_matrix (Matrix.identity ()); - + if (has_stroke) { context.stroke_extents (out x0, out y0, out x1, out y1); } else { context.fill_extents (out x0, out y0, out x1, out y1); } - + + Matrix matrix = context.get_matrix (); + matrix.transform_point (ref x0, ref y0); + matrix.transform_point (ref x1, ref y1); + + context.fill (); context.restore (); left = x0;
--- a/libsvgbird/Rectangle.vala +++ b/libsvgbird/Rectangle.vala @@ -32,7 +32,7 @@ } public override bool is_over (double x, double y) { - return false; + return this.x <= x <= this.x + width && this.y <= y <= this.y + height; } public override void draw_outline (Context cr) {
--- a/libsvgbird/SvgDrawing.vala +++ b/libsvgbird/SvgDrawing.vala @@ -55,8 +55,8 @@ public override void apply_transform (Context cr) { apply_view_box (cr); - root_layer.apply_transform (cr); base.apply_transform (cr); + root_layer.apply_transform (cr); } public void draw (Context cr) {
--- a/libsvgbird/SvgPath.vala +++ b/libsvgbird/SvgPath.vala @@ -13,6 +13,7 @@ */ using Cairo; + using Math; namespace SvgBird { @@ -21,6 +22,8 @@ double pen_position_x = 0; double pen_position_y = 0; + + public delegate bool LineIterator (double x, double y, double step); public SvgPath () { } @@ -31,15 +34,154 @@ foreach (Points point_data in p.points) { points.add (point_data.copy ()); } + } + + public override bool is_over (double point_x, double point_y) { + bool inside = false; + + double x = point_x; + double y = point_y; + + Matrix matrix = view_matrix; + matrix.invert (); + matrix.transform_point (ref x, ref y); + + if (is_over_boundaries (point_x, point_y)) { + foreach (Points p in points) { + if (is_over_points (p, point_x, point_y)) { + inside = !inside; + } + } + } + + return inside; } - public override bool is_over (double x, double y) { - return false; + public bool is_over_points (Points p, double point_x, double point_y) { + double previous_x; + double previous_y; + bool inside = false; + + PointValue* points = p.point_data.data; + int size = p.point_data.size; + + return_if_fail (size % 8 == 0); + + get_start (p, out previous_x, out previous_y); + + for (int i = 0; i < size; i += 8) { + switch (points[i].type) { + case POINT_ARC: + double rx = points[i + 1].value; + double ry = points[i + 2].value; + double rotation = points[i + 3].value; + double large_arc = points[i + 4].value; + double sweep = points[i + 5].value; + double dest_x = points[i + 6].value; + double dest_y = points[i + 7].value; + + double angle_start, angle_extent, cx, cy; + + get_arc_arguments (pen_position_x, pen_position_y, rx, ry, + rotation, large_arc > 0, sweep > 0, dest_x, dest_y, + out angle_start, out angle_extent, + out cx, out cy); + const int steps = 50; + for (int step = 0; step < steps; step++) { + double angle = angle_start + step * (angle_extent / steps); + double next_x = cx + cos (angle); + double next_y = cy + sin (angle); + is_inside (ref inside, + point_x, point_y, + previous_x, previous_y, + next_x, next_y); + + previous_x = next_x; + previous_y = next_y; + } + break; + case POINT_CUBIC: + all_lines (previous_x, previous_y, + points[i + 1].value, points[i + 2].value, + points[i + 3].value, points[i + 4].value, + points[i + 5].value, points[i + 6].value, + (x, y, t) => { + is_inside (ref inside, + point_x, point_y, + previous_x, previous_y, + x, y); + + previous_x = x; + previous_y = y; + return true; + }); + + previous_x = points[i + 5].value; + previous_y = points[i + 6].value; + break; + case POINT_LINE: + is_inside (ref inside, point_x, point_y, previous_x, previous_y, + points[i + 1].value, points[i + 2].value); + previous_x = points[i + 1].value; + previous_y = points[i + 2].value; + break; + } + } + + return inside; + } + + static void is_inside (ref bool inside, double point_x, double point_y, + double prev_x, double prev_y, double next_x, double next_y) { + if ((next_y > point_y) != (prev_y > point_y) + && point_x < (prev_x - next_x) * (point_y - next_y) / (prev_y - next_y) + next_x) { + inside = !inside; + print (@"flip\n"); + } } + private static bool all_lines (double x0, double y0, double x1, double y1, double x2, double y2, double x3, double y3, + LineIterator iter, double steps = 400) { + double px = x1; + double py = y1; + + double t; + + for (int i = 0; i < steps; i++) { + t = i / steps; + + px = bezier_path (t, x0, x1, x2, x3); + py = bezier_path (t, y0, y1, y2, y3); + + if (!iter (px, py, t)) { + return false; + } + } + + return true; + } + + public static double bezier_path (double step, double p0, double p1, double p2, double p3) { + double q0, q1, q2; + double r0, r1; + + q0 = step * (p1 - p0) + p0; + q1 = step * (p2 - p1) + p1; + q2 = step * (p3 - p2) + p2; + + r0 = step * (q1 - q0) + q0; + r1 = step * (q2 - q1) + q1; + + return step * (r1 - r0) + r0; + } + public override void draw_outline (Context cr) { foreach (Points p in points) { - move_to_start (cr, p); + double x, y; + + get_start (p, out x, out y); + cr.move_to (x, y); + draw_points (cr, p); if (p.closed) { @@ -48,22 +190,28 @@ } } - public void move_to_start (Context cr, Points path) { + public void get_start (Points path, out double x, out double y) { int size = path.point_data.size; + + x = 0; + y = 0; // points are padded up to 8 units return_if_fail (size % 8 == 0); return_if_fail (size >= 8); switch (path.get_point_type (0)) { - case POINT_ARC: - cr.move_to (path.get_double (6), path.get_double (7)); + case POINT_ARC: + x = path.get_double (6); + y = path.get_double (7); break; case POINT_CUBIC: - cr.move_to (path.get_double (5), path.get_double (6)); + x = path.get_double (5); + y = path.get_double (6); break; case POINT_LINE: - cr.move_to (path.get_double (1), path.get_double (2)); + x = path.get_double (1); + y = path.get_double (2); break; default: warning (@"Unknown type $(path.get_point_type (0))"); @@ -102,7 +250,7 @@ pen_position_y = points[i + 2].value; break; } - } + } } void draw_arc (Context cr,