Clone in a terminal:
Commit 7bf31d8
Johan Mattsson - 2016-07-15T13:47:12+00:00
7bf31d87cebbf64827bce0e543a12dcd62f0a9f9johan.mattsson.m@gmail.com

Select SVG objects

Changed files (6)

Diff

diff --git a/libsvgbird/Circle.vala b/libsvgbird/Circle.valaindex 5a3b178..aacacf3 100644--- a/libsvgbird/Circle.vala+++ b/libsvgbird/Circle.vala@@ -26,7 +26,9 @@ public class Circle : Object { 	} 	 	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) {diff --git a/libsvgbird/Ellipse.vala b/libsvgbird/Ellipse.valaindex 07b0ad7..df30840 100644--- a/libsvgbird/Ellipse.vala+++ b/libsvgbird/Ellipse.vala@@ -28,7 +28,9 @@ public class Ellipse : Object { 	} 	 	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) {diff --git a/libsvgbird/Object.vala b/libsvgbird/Object.valaindex 30cf07f..bc8a6ca 100644--- a/libsvgbird/Object.vala+++ b/libsvgbird/Object.vala@@ -93,7 +93,10 @@ public abstract class Object : GLib.Object { 	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 ();@@ -128,6 +131,10 @@ public abstract class Object : GLib.Object { 		return "Object"; 	} +	public bool is_over_boundaries (double x, double y) {+		return top <= y <= bottom  && left <= x <= right;+	}+ 	public void paint (Context cr) { 		Color fill, stroke; 		bool need_fill = (style.fill_gradient != null || style.fill != null);@@ -214,6 +221,8 @@ public abstract class Object : GLib.Object { 		double x0, y0, x1, y1; 		bool has_stroke = style.has_stroke (); +		apply_transform (context);+ 		if (has_stroke) { 			context.set_line_width (style.stroke_width); 		} else {@@ -223,15 +232,18 @@ public abstract class Object : GLib.Object { 		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;diff --git a/libsvgbird/Rectangle.vala b/libsvgbird/Rectangle.valaindex 0fcee4e..b669024 100644--- a/libsvgbird/Rectangle.vala+++ b/libsvgbird/Rectangle.vala@@ -32,7 +32,7 @@ public class Rectangle : Object { 	} 	 	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) {diff --git a/libsvgbird/SvgDrawing.vala b/libsvgbird/SvgDrawing.valaindex 7fcf6d8..418db2c 100644--- a/libsvgbird/SvgDrawing.vala+++ b/libsvgbird/SvgDrawing.vala@@ -55,8 +55,8 @@ public class SvgDrawing : Object {  	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) {diff --git a/libsvgbird/SvgPath.vala b/libsvgbird/SvgPath.valaindex 34435dc..0b28730 100644--- a/libsvgbird/SvgPath.vala+++ b/libsvgbird/SvgPath.vala@@ -13,6 +13,7 @@ */  using Cairo;+using Math;  namespace SvgBird { @@ -22,6 +23,8 @@ public class SvgPath : Object { 	double pen_position_x = 0; 	double pen_position_y = 0; 	+	public delegate bool LineIterator (double x, double y, double step);	+	 	public SvgPath () { 	} @@ -32,14 +35,153 @@ public class SvgPath : Object { 			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 class SvgPath : Object { 		} 	} -	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 @@ public class SvgPath : Object { 				pen_position_y = points[i + 2].value; 				break; 			}-		}		+		} 	} 				 	void draw_arc (Context cr,

Contact

Email: johan.mattsson.m@gmail.com
Mastodon: typo.social/@birdfont
GitHub: johanmattssonm
LinkedIn: johan-mattsson-2ab324112