Clone in a terminal:
Commit 904b358
Johan Mattsson - 2014-07-11T16:08:37+00:00
904b358b0ecad4a9b2702a6af6a5731ddb8dd459johan.mattsson.m@gmail.com

Svg transform and a fix for a crash bug in ClickMap

Changed files (13)

Diff

diff --git a/libbirdfont/BirdFontFile.vala b/libbirdfont/BirdFontFile.valaindex bf6ff58..6f27974 100644--- a/libbirdfont/BirdFontFile.vala+++ b/libbirdfont/BirdFontFile.vala@@ -472,8 +472,8 @@ class BirdFontFile : GLib.Object { 		EditPointHandle h = start.get_right_handle (); 		string x0, y0, x1, y1; 		-		x0 = round (h.x ());-		y0 = round (h.y ());+		x0 = round (h.x);+		y0 = round (h.y); 		x1 = round (end.x); 		y1 = round (end.y); 	@@ -485,10 +485,10 @@ class BirdFontFile : GLib.Object { 		EditPointHandle h2 = end.get_left_handle (); 		string x0, y0, x1, y1, x2, y2; -		x0 = round (h1.x ());-		y0 = round (h1.y ());-		x1 = round (h2.x ());-		y1 = round (h2.y ());+		x0 = round (h1.x);+		y0 = round (h1.y);+		x1 = round (h2.x);+		y1 = round (h2.y); 		x2 = round (end.x); 		y2 = round (end.y); @@ -500,10 +500,10 @@ class BirdFontFile : GLib.Object { 		EditPointHandle h2 = end.get_left_handle (); 		string x0, y0, x1, y1, x2, y2; -		x0 = round (h1.x ());-		y0 = round (h1.y ());-		x1 = round (h2.x ());-		y1 = round (h2.y ());+		x0 = round (h1.x);+		y0 = round (h1.y);+		x1 = round (h2.x);+		y1 = round (h2.y); 		x2 = round (end.x); 		y2 = round (end.y); diff --git a/libbirdfont/ClickMap.vala b/libbirdfont/ClickMap.valanew file mode 100644index 0000000..1dcce99--- /dev/null+++ b/libbirdfont/ClickMap.vala@@ -0,0 +1,189 @@+/*+    Copyright (C) 2014 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 +    published by the Free Software Foundation; either version 3 of the +    License, or (at your option) any later version.++    This library is distributed in the hope that it will be useful, but +    WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +    Lesser General Public License for more details.+*/++namespace BirdFont {++// This is a refcounted container in order to avoid double free +// corruption in lambda functions.+public class ClickMap : GLib.Object {+	char* map;+	int width;+	int margin;+	int map_size;++	public ClickMap (int width) {+		this.width = width;+		margin = 10;+		map_size = width + margin;+		map = malloc (map_size * map_size);+	}+	+	~ClickMap () {+		delete map;+	}+	+	public char get_value (int x, int y) {+		+		if (unlikely (!(0 <= x < map_size && 0 <= y < map_size))) {+			warning ("Array index out of bounds.");+			return '\0';+		}+		+		return map[y * width + x];+	}+	+	public void set_value (int x, int y, char val) {+		if (unlikely (!(0 <= x < map_size && 0 <= y < map_size))) {+			warning ("Array index out of bounds.");+			return;+		}+		+		map[y * width + x] = val;+	}++	private void map_outline (Path path) {+		path.all_of_path ((cx, cy, ct) => {+			int px = (int) (width * ((cx - path.xmin) / (path.xmax - path.xmin)));+			int py = (int) (width * ((cy - path.ymin) / (path.ymax - path.ymin)));+			+			set_value (px, py, '#');+			+			return true;+		}, 2 * width);+	}++	private void close_outline (Path path) {+		// first to last point in case the path is open+		Path.all_of (path.get_last_point (), path.get_first_point (), (cx, cy, ct) => {+			int px = (int) (width * ((cx - path.xmin) / (path.xmax - path.xmin)));+			int py = (int) (width * ((cy - path.ymin) / (path.ymax - path.ymin)));+			+			set_value (px, py, '#');+			+			return true;+		}, 2 * width);+	}+	+	public void create_click_map (Path path) {+		// Clear the map+		for (int i = 0; i < map_size; i++) {+			for (int j = 0; j < map_size; j++) {+				set_value (i, j, '\0');+			}+		}+		+		// Create outline+		map_outline (path);+		close_outline (path);+		+		// Fill the map+		for (int j = 0; j < width; j++) {+			for (int k = 0; k < width; k++) {+				if (get_value (k, j) == '#') {+					+					k++;+					while (k < width && get_value (k, j) == '#') {+						k++;+					}++					while (k < width && get_value (k, j) == '\0') {+						set_value (k, j, 'o');+						k++;+					}++					k++;+					while (k < width && get_value (k, j) == '#') {+						k++;+					}+				}+			}+		}++		// Remove fill from the out side+		for (int k = 0; k < width; k++) {+			+			if (get_value (k, 0) == 'o') {+				set_value (k, 0, '\0'); +			}+			+			for (int l = width - 1; l >= 0; l--) {+				if (get_value (k, l) != '#') {+					if (get_value (k, l + 1) == '\0') {+						set_value (k, l, '\0');+					}+					+					if (get_value (k, l + 1) == 'o') {+						set_value (k, l, 'o');+					}+				}+			}+		} ++		for (int k = 0; k < width; k++) {+			if (get_value (0, k) == 'o') {+				set_value (0, k,'\0'); +			}+			+			for (int l = width - 1; l >= 0; l--) {+				if (get_value (l, k) != '#') {+					if (get_value (l + 1, k) == '\0') {+						set_value (l, k, '\0');+					}+					+					if (get_value (l + 1, k) == 'o') {+						set_value (l, k, 'o');+					}+				}+			}+		}++		for (int k = width - 1; k > 0; k--) {+			if (get_value (k, 0) == 'o') {+				set_value (k, 0,'\0'); +			}+			+			for (int l = width - 1; l >= 0; l--) {+				if (get_value (k, l) != '#') {				+					if (get_value (k, l + 1) == 'o') {+						set_value (k, l, 'o');+					}+				}+			}+		}+	}+	+	public void print () {+		char c;+		for (int i = width - 1; i >= 0; i--) {+			for (int j = 0; j < width; j++) {+				c = get_value (j, i);+				if (c == '\0') {+					stdout.printf (" ");+				} else if (c == '#') {+					stdout.printf ("#");+				} else if (c == 'o') {+					stdout.printf ("o");+				} else if (c == 'X') {+					stdout.printf ("X");+				} else {+					stdout.printf ("?");+				}+			}+			+			stdout.printf ("\n");+		}+	}+}++}diff --git a/libbirdfont/EditPoint.vala b/libbirdfont/EditPoint.valaindex 5f175ed..44a6660 100644--- a/libbirdfont/EditPoint.vala+++ b/libbirdfont/EditPoint.vala@@ -49,7 +49,34 @@ public class EditPoint { 	 	public bool tie_handles = false; 	public bool reflective_handles = false;-	++	/** Set new position for control point without moving handles. */+	public double independent_x {+		get { +			return x;+		}+		+		set { +			double d = value - x;+			x = value;+			right_handle.x -= d;+			left_handle.x -= d;+		}+	}++	public double independent_y {+		get {+			return y;	+		}+		+		set { +			double d = value - y;+			y = value;+			right_handle.y -= d;+			left_handle.y -= d;+		}+	}+		 	public EditPoint (double nx = 0, double ny = 0, PointType nt = PointType.NONE) { 		x = nx; 		y = ny;@@ -93,10 +120,10 @@ public class EditPoint { 	public bool equals (EditPoint e) { 		return e.x == x  			&& e.y == y -			&& get_right_handle ().x () == e.get_right_handle ().x ()-			&& get_right_handle ().y () == e.get_right_handle ().y ()-			&& get_left_handle ().x () == e.get_left_handle ().x ()-			&& get_left_handle ().y () == e.get_left_handle ().y ();+			&& get_right_handle ().x == e.get_right_handle ().x+			&& get_right_handle ().y == e.get_right_handle ().y+			&& get_left_handle ().x == e.get_left_handle ().x+			&& get_left_handle ().y == e.get_left_handle ().y; 	}  	/** Make handles symmetrical. */@@ -118,8 +145,8 @@ public class EditPoint { 		px = get_next ().get_next ().x; 		py = get_next ().get_next ().y; 		-		dr = Math.sqrt (Math.pow (px - right_handle.x (), 2) + Math.pow (py - right_handle.y (), 2));-		dl = Math.sqrt (Math.pow (px - left_handle.x (), 2) + Math.pow (py - left_handle.y (), 2));+		dr = Math.sqrt (Math.pow (px - right_handle.x, 2) + Math.pow (py - right_handle.y, 2));+		dl = Math.sqrt (Math.pow (px - left_handle.x, 2) + Math.pow (py - left_handle.y, 2));  		// flip handles 		if (dl < dr) {@@ -283,8 +310,8 @@ public class EditPoint { 		 		eh = right_handle; 		-		a = left_handle.x () - right_handle.x ();-		b = left_handle.y () - right_handle.y ();+		a = left_handle.x - right_handle.x;+		b = left_handle.y - right_handle.y; 		c = a * a + b * b; 		 		if (c == 0) {@@ -293,7 +320,7 @@ public class EditPoint { 		 		length = sqrt (fabs (c)); 		-		if (right_handle.y () < left_handle.y ()) {+		if (right_handle.y < left_handle.y) { 			angle = acos (a / length) + PI; 		} else { 			angle = -acos (a / length) + PI;@@ -311,7 +338,7 @@ public class EditPoint { 		left_handle.angle = angle - PI;  		set_tie_handle (true);-		eh.move_to_coordinate (right_handle.x (), right_handle.y ());+		eh.move_to_coordinate (right_handle.x, right_handle.y); 	}  	public EditPoint copy () {@@ -387,7 +414,7 @@ public class EditPoint { 				n = get_next (); 				n.set_tie_handle (false); 				n.set_reflective_handles (false);-				n.left_handle.move_to_coordinate_internal (right_handle.x (), right_handle.y ());+				n.left_handle.move_to_coordinate_internal (right_handle.x, right_handle.y); 			} 		} 		@@ -396,7 +423,7 @@ public class EditPoint { 				p = get_prev (); 				p.set_tie_handle (false); 				p.set_reflective_handles (false);-				p.right_handle.move_to_coordinate (left_handle.x (), left_handle.y ());+				p.right_handle.move_to_coordinate (left_handle.x, left_handle.y); 			} 		} 	}diff --git a/libbirdfont/EditPointHandle.vala b/libbirdfont/EditPointHandle.valaindex f0f96d3..6b603b9 100644--- a/libbirdfont/EditPointHandle.vala+++ b/libbirdfont/EditPointHandle.vala@@ -28,6 +28,36 @@ public class EditPointHandle  {  	public double angle; +	public double x {+		get { +			double r = px ();	+			+			if (unlikely (r <= -100000)) {+				print_position ();+				move_to (0, 0);+			}+		+			return r;+		}+		+		set { move_to_coordinate_internal (value, py ()); }+	}++	public double y {+		get {+			double r = py ();+		+			if (unlikely (r <= -100000)) {+				print_position ();+				move_to (0, 0);+			}+			+			return r;	+		}+		+		set { move_to_coordinate_internal (px (), value); }+	}+	 	public EditPointHandle.empty() { 		this.parent = none; 		this.angle = 0;@@ -80,28 +110,6 @@ public class EditPointHandle  { 	public void set_point_type (PointType point_type) { 		type = point_type; 	}--	public double x () {-		double r = px ();-		-		if (unlikely (r <= -100000)) {-			print_position ();-			move_to (0, 0);-		}-	-		return r;-	}-	-	public double y () {-		double r = py ();-		-		if (unlikely (r <= -100000)) {-			print_position ();-			move_to (0, 0);-		}-		-		return r;-	} 	 	double px () { 		assert ((EditPoint?) parent != null);@@ -127,8 +135,8 @@ public class EditPointHandle  { 		} 	 		p = (!) visual_handle;-		p.x = x ();-		p.y = y ();+		p.x = x;+		p.y = y; 		 		return p; 	}diff --git a/libbirdfont/FastPath.vala b/libbirdfont/FastPath.valaindex 1a1d341..f5e2873 100644--- a/libbirdfont/FastPath.vala+++ b/libbirdfont/FastPath.vala@@ -80,10 +80,10 @@ public class FastPath : GLib.Object { 	public void set_editpoint (int index, EditPoint ep) { 		points[NUMBERS_PER_POINT * index + POS_X] = ep.x; 		points[NUMBERS_PER_POINT * index + POS_Y] = ep.y;-		points[NUMBERS_PER_POINT * index + LEFT_HANDLE_POS_X] = ep.get_left_handle ().x ();-		points[NUMBERS_PER_POINT * index + LEFT_HANDLE_POS_Y] = ep.get_left_handle ().y ();-		points[NUMBERS_PER_POINT * index + RIGHT_HANDLE_POS_X] = ep.get_right_handle ().x ();-		points[NUMBERS_PER_POINT * index + RIGHT_HANDLE_POS_Y] = ep.get_right_handle ().y ();+		points[NUMBERS_PER_POINT * index + LEFT_HANDLE_POS_X] = ep.get_left_handle ().x;+		points[NUMBERS_PER_POINT * index + LEFT_HANDLE_POS_Y] = ep.get_left_handle ().y;+		points[NUMBERS_PER_POINT * index + RIGHT_HANDLE_POS_X] = ep.get_right_handle ().x;+		points[NUMBERS_PER_POINT * index + RIGHT_HANDLE_POS_Y] = ep.get_right_handle ().y; 	}  	public double get_x (int index) {diff --git a/libbirdfont/OpenFontFormat/GlyfData.vala b/libbirdfont/OpenFontFormat/GlyfData.valaindex 418e1a5..1f64404 100644--- a/libbirdfont/OpenFontFormat/GlyfData.vala+++ b/libbirdfont/OpenFontFormat/GlyfData.vala@@ -201,10 +201,10 @@ class GlyfData : GLib.Object { 				type = e.get_right_handle ().type; 				 				// off curve-				x = rint (e.get_right_handle ().x () * UNITS - prev - glyph.left_limit * UNITS);+				x = rint (e.get_right_handle ().x * UNITS - prev - glyph.left_limit * UNITS); 				coordinate_x.append ((int16) x); 				-				prev = rint (e.get_right_handle ().x () * UNITS - glyph.left_limit * UNITS);+				prev = rint (e.get_right_handle ().x * UNITS - glyph.left_limit * UNITS); 			} 		} 	}@@ -225,10 +225,10 @@ class GlyfData : GLib.Object { 				type = e.get_right_handle ().type; 				 				// off curve-				y = rint (e.get_right_handle ().y () * UNITS - prev - font.base_line * UNITS);+				y = rint (e.get_right_handle ().y * UNITS - prev - font.base_line * UNITS); 				coordinate_y.append ((int16) y); 			-				prev = rint (e.get_right_handle ().y () * UNITS - font.base_line  * UNITS);+				prev = rint (e.get_right_handle ().y * UNITS - font.base_line  * UNITS); 			} 		} 	}diff --git a/libbirdfont/OpenFontFormat/GlyfTable.vala b/libbirdfont/OpenFontFormat/GlyfTable.valaindex e2c605d..eb49eaf 100644--- a/libbirdfont/OpenFontFormat/GlyfTable.vala+++ b/libbirdfont/OpenFontFormat/GlyfTable.vala@@ -707,8 +707,8 @@ public class GlyfTable : Table { 				} else { 									 					if (prev_is_curve) {-						x = x - (x - edit_point.right_handle.x ()) / 2;-						y = y - (y - edit_point.right_handle.y ()) / 2;+						x = x - (x - edit_point.right_handle.x) / 2;+						y = y - (y - edit_point.right_handle.y) / 2;  						edit_point = new EditPoint (); 						edit_point.set_position (x, y);@@ -734,8 +734,8 @@ public class GlyfTable : Table { 				x = xcoordinates[first_point] * 1000.0 / units_per_em; // in proportion to em width 				y = ycoordinates[first_point] * 1000.0 / units_per_em; 				-				x = x - (x - edit_point.right_handle.x ()) / 2;-				y = y - (y - edit_point.right_handle.y ()) / 2;+				x = x - (x - edit_point.right_handle.x) / 2;+				y = y - (y - edit_point.right_handle.y) / 2; 				 				edit_point = new EditPoint (); 				edit_point.set_position (x, y);diff --git a/libbirdfont/Path.vala b/libbirdfont/Path.valaindex 6d3c112..c1649bd 100644--- a/libbirdfont/Path.vala+++ b/libbirdfont/Path.vala@@ -306,8 +306,8 @@ public class Path { 		EditPoint middle; 		double x, y; 		-		x = e.get_right_handle ().x () + (en.get_left_handle ().x () - e.get_right_handle ().x ()) / 2;-		y = e.get_right_handle ().y () + (en.get_left_handle ().y () - e.get_right_handle ().y ()) / 2;+		x = e.get_right_handle ().x + (en.get_left_handle ().x - e.get_right_handle ().x) / 2;+		y = e.get_right_handle ().y + (en.get_left_handle ().y - e.get_right_handle ().y) / 2; 		 		middle = new EditPoint (x, y, PointType.DOUBLE_CURVE); 		middle.right_handle = en.get_left_handle ().copy ();@@ -351,11 +351,11 @@ public class Path { 		xa = center_x + e.x; 		ya = center_y - e.y; -		xb = center_x + e.get_right_handle ().x ();-		yb = center_y - e.get_right_handle ().y ();+		xb = center_x + e.get_right_handle ().x;+		yb = center_y - e.get_right_handle ().y; 		-		xc = center_x + en.get_left_handle ().x ();-		yc = center_y - en.get_left_handle ().y ();+		xc = center_x + en.get_left_handle ().x;+		yc = center_y - en.get_left_handle ().y; 		 		xd = center_x + en.x; 		yd = center_y - en.y;		@@ -366,11 +366,11 @@ public class Path { 		xa =  + e.x; 		ya =  - e.y; -		xb =  + e.get_right_handle ().x ();-		yb =  - e.get_right_handle ().y ();+		xb =  + e.get_right_handle ().x;+		yb =  - e.get_right_handle ().y; 		-		xc =  + en.get_left_handle ().x ();-		yc =  - en.get_left_handle ().y ();+		xc =  + en.get_left_handle ().x;+		yc =  - en.get_left_handle ().y; 		 		xd =  + en.x; 		yd =  - en.y;		@@ -436,12 +436,12 @@ public class Path {  			if (!(is_open () && e == points.get (points.size - 1))) { 				draw_line (handle_right, e, cr, 0.15);-				draw_image (cr, img_right, e.get_right_handle ().x (), e.get_right_handle ().y ());+				draw_image (cr, img_right, e.get_right_handle ().x, e.get_right_handle ().y); 			} 			 			if (!(is_open () && e == points.get (0))) { 				draw_line (handle_left, e, cr, 0.15);-				draw_image (cr, img_left, e.get_left_handle ().x (), e.get_left_handle ().y ());+				draw_image (cr, img_left, e.get_left_handle ().x, e.get_left_handle ().y); 			} 		} 	}@@ -617,6 +617,23 @@ public class Path { 		ymin *= ratio; 		ymax *= ratio; 	}++	public void scale (double scale_x, double scale_y) {		+		foreach (EditPoint p in points) {+			p.right_handle.length *= scale_x * scale_y;+			p.left_handle.length *= scale_x * scale_y;+		}+		+		foreach (EditPoint p in points) {+			p.x *= scale_x;+			p.y *= scale_y;+		}+		+		xmin *= scale_x;	+		xmax *= scale_x;+		ymin *= scale_y;+		ymax *= scale_y;+	} 	 	public Path copy () { 		Path new_path = new Path ();@@ -666,30 +683,30 @@ public class Path { 	public static double get_length_from (EditPoint a, EditPoint b) { 		double x, y; 		-		x = Math.fabs (a.x - a.get_right_handle ().x ());-		x += Math.fabs (a.get_right_handle ().x () - b.get_left_handle ().x ());-		x += Math.fabs (b.get_left_handle ().x () - b.x);+		x = Math.fabs (a.x - a.get_right_handle ().x);+		x += Math.fabs (a.get_right_handle ().x - b.get_left_handle ().x );+		x += Math.fabs (b.get_left_handle ().x - b.x); -		y = Math.fabs (a.y - a.get_right_handle ().y ());-		y += Math.fabs (a.get_right_handle ().y () - b.get_left_handle ().y ());-		y += Math.fabs (b.get_left_handle ().y () - b.y);+		y = Math.fabs (a.y - a.get_right_handle ().y);+		y += Math.fabs (a.get_right_handle ().y - b.get_left_handle ().y);+		y += Math.fabs (b.get_left_handle ().y - b.y); 		 		return Math.fabs (Math.sqrt (x * x + y * y)); 	} -	+ 	/** Variable precision */ 	public bool is_over_coordinate_var (double x, double y) { 		PathList pathlist;-		bool result = false;+		bool in_path = false; 		int width;-		char[,] click_map;+		ClickMap click_map; 		int px, py; 		int click_x, click_y; 		 		if (points.size < 2) { 			return false; 		}-		+ 		if (stroke > 0) { 			pathlist = StrokeTool.get_stroke (this, stroke); 			@@ -706,96 +723,25 @@ public class Path { 			return false; 		} 		+		 		// generate a rasterized image of the object-		width = 512;-		click_map = new char[width + 1, width + 1];+		width = 80;+		click_map = new ClickMap (width); 		px = 0; 		py = 0;-		all_of_path ((cx, cy, ct) => {-			px = (int) (width * ((cx - xmin) / (xmax - xmin)));-			py = (int) (width * ((cy - ymin) / (ymax - ymin)));-			click_map[px, py] = '#';-			return true;-		}, 2 * width); 		-		// first to last point in case the path is open-		all_of (get_last_point (), get_first_point (), (cx, cy, ct) => {-			px = (int) (width * ((cx - xmin) / (xmax - xmin)));-			py = (int) (width * ((cy - ymin) / (ymax - ymin)));-			click_map[px, py] = '#';-			return true;-		}, 2 * width);-	-		// Fill the map-		for (int j = 0; j < width; j++) {-			for (int k = 0; k < width; k++) {-				if (click_map[k, j] == '#') {-					-					k++;-					while (k < width && click_map[k, j] == '#') {-						k++;-					}--					while (k < width && click_map[k, j] == '\0') {-						click_map[k, j] = 'o';-						k++;-					}--					k++;-					while (k < width && click_map[k, j] == '#') {-						k++;-					}-				}-			}-		}--		// remove fill from the out side-		for (int k = 0; k < width; k++) {-			-			if (click_map[k, 0] == 'o') {-				click_map[k, 0] = '\0'; -			}-			-			for (int l = width - 1; l >= 0; l--) {-				if (click_map[k, l] != '#') {-					if (click_map[k, l + 1] == '\0') {-						click_map[k, l] = '\0';	-					}-					-					if (click_map[k, l + 1] == 'o') {-						click_map[k, l] = 'o';	-					}-				}-			}-		} --		for (int k = 0; k < width; k++) {-			-			if (click_map[0, k] == 'o') {-				click_map[0, k] = '\0'; -			}-			-			for (int l = width - 1; l >= 0; l--) {-				if (click_map[l, k] != '#') {-					if (click_map[l + 1, k] == '\0') {-						click_map[l, k] = '\0';	-					}-					-					if (click_map[l + 1, k] == 'o') {-						click_map[l, k] = 'o';	-					}-				}-			}-		}+		click_map.create_click_map (this);  		click_x = (int) (width * ((x - xmin) / (xmax - xmin))); 		click_y = (int) (width * ((y - ymin) / (ymax - ymin))); -		result = (click_map[click_x, click_y] != '\0');+		in_path = click_map.get_value (click_x, click_y) != '\0'; -		click_map[click_x, click_y] = 'X';+		click_map.set_value (click_x, click_y, 'X');+		+		click_map.print (); 		-		return result;+		return in_path; 	} 	 	public bool is_over_boundry (double x, double y) {@@ -951,20 +897,20 @@ public class Path { 	}  	private void update_region_boundaries_for_handle (EditPointHandle h) {-		if (h.x () > xmax) {-			xmax = h.x ();+		if (h.x > xmax) {+			xmax = h.x; 		} -		if (h.x () < xmin) {-			xmin = h.x ();+		if (h.x < xmin) {+			xmin = h.x; 		} -		if (h.y () > ymax) {-			ymax = h.y ();+		if (h.y > ymax) {+			ymax = h.y; 		} -		if (h.y () < ymin) {-			ymin = h.y ();+		if (h.y < ymin) {+			ymin = h.y; 		} 	} @@ -1068,11 +1014,11 @@ public class Path { 				first.get_right_handle ().type = PointType.QUADRATIC;  				// half way between handles-				x = first.get_right_handle ().x () + (next.get_left_handle ().x () - first.get_right_handle ().x ()) / 2;-				y = first.get_right_handle ().y () + (next.get_left_handle ().y () - first.get_right_handle ().y ()) / 2;+				x = first.get_right_handle ().x + (next.get_left_handle ().x - first.get_right_handle ().x) / 2;+				y = first.get_right_handle ().y + (next.get_left_handle ().y - first.get_right_handle ().y) / 2; 				 				hidden = new EditPoint (x, y, PointType.QUADRATIC);-				hidden.right_handle.move_to_coordinate_internal (next.get_left_handle ().x(), next.get_left_handle ().y());+				hidden.right_handle.move_to_coordinate_internal (next.get_left_handle ().x, next.get_left_handle ().y); 				hidden.get_right_handle ().type = PointType.QUADRATIC; 				 				hidden.get_left_handle ().type = PointType.QUADRATIC;@@ -1148,7 +1094,7 @@ public class Path {  		foreach (EditPoint ep in quadratic_path.points) { 			if (ep.type == PointType.QUADRATIC) {-				ep.get_left_handle ().move_to_coordinate (ep.get_prev ().get_right_handle ().x (), ep.get_prev ().get_right_handle ().y ());+				ep.get_left_handle ().move_to_coordinate (ep.get_prev ().get_right_handle ().x, ep.get_prev ().get_right_handle ().y); 			} 		} @@ -1230,8 +1176,8 @@ public class Path { 		prev.get_right_handle ().type = PointType.QUADRATIC; 		prev.get_right_handle ().move_delta (0.000001, 0.000001); 		-		x = prev.get_right_handle ().x ();-		y = prev.get_right_handle ().y ();+		x = prev.get_right_handle ().x;+		y = prev.get_right_handle ().y; 		 		ep.get_left_handle ().move_to_coordinate (ep.x - (ep.x - prev.x) / 2,  			ep.y - (ep.y - prev.y) / 2);		@@ -1295,8 +1241,8 @@ public class Path { 		});  		if (right == PointType.DOUBLE_CURVE || left == PointType.DOUBLE_CURVE) {-			double_bezier_vector (position, start.x, start.get_right_handle ().x (), stop.get_left_handle ().x (), stop.x, out x0, out x1);-			double_bezier_vector (position, start.y, start.get_right_handle ().y (), stop.get_left_handle ().y (), stop.y, out y0, out y1);+			double_bezier_vector (position, start.x, start.get_right_handle ().x, stop.get_left_handle ().x, stop.x, out x0, out x1);+			double_bezier_vector (position, start.y, start.get_right_handle ().x, stop.get_left_handle ().y, stop.y, out y0, out y1);  			ep.get_left_handle ().set_point_type (PointType.DOUBLE_CURVE);	 			ep.get_right_handle ().set_point_type (PointType.DOUBLE_CURVE);@@ -1306,8 +1252,8 @@ public class Path {  			ep.type = PointType.DOUBLE_CURVE; 		} else if (right == PointType.QUADRATIC) {		-			x0 = quadratic_bezier_vector (1 - position, stop.x, start.get_right_handle ().x (), start.x);-			y0 = quadratic_bezier_vector (1 - position, stop.y, start.get_right_handle ().y (), start.y);+			x0 = quadratic_bezier_vector (1 - position, stop.x, start.get_right_handle ().x, start.x);+			y0 = quadratic_bezier_vector (1 - position, stop.y, start.get_right_handle ().x, start.y); 			ep.get_right_handle ().move_to_coordinate (x0, y0); 			 			ep.get_left_handle ().set_point_type (PointType.QUADRATIC);	@@ -1317,8 +1263,8 @@ public class Path { 			 			ep.type = PointType.QUADRATIC;				 		} else if (right == PointType.CUBIC || left == PointType.CUBIC) {-			bezier_vector (position, start.x, start.get_right_handle ().x (), stop.get_left_handle ().x (), stop.x, out x0, out x1);-			bezier_vector (position, start.y, start.get_right_handle ().y (), stop.get_left_handle ().y (), stop.y, out y0, out y1);+			bezier_vector (position, start.x, start.get_right_handle ().x, stop.get_left_handle ().x, stop.x, out x0, out x1);+			bezier_vector (position, start.y, start.get_right_handle ().x, stop.get_left_handle ().y, stop.y, out y0, out y1);  			ep.get_left_handle ().set_point_type (PointType.CUBIC); 			ep.get_left_handle ().move_to_coordinate (x0, y0);@@ -1350,8 +1296,8 @@ public class Path { 		if (right == PointType.QUADRATIC) { // update connected handle 			if (ep.prev != null) { 				ep.get_left_handle ().move_to_coordinate_internal (-					ep.get_prev ().right_handle.x (), -					ep.get_prev ().right_handle.y ());+					ep.get_prev ().right_handle.x, +					ep.get_prev ().right_handle.y);  			} else { 				warning ("ep.prev is null for quadratic point");@@ -1468,8 +1414,8 @@ public class Path { 		next = (!) next_point;  // 		// FIXME: delete-		bezier_vector (step, previous.x, previous.get_right_handle ().x (), next.get_left_handle ().x (), next.x, out handle_x0, out handle_x1);-		bezier_vector (step, previous.y, previous.get_right_handle ().y (), next.get_left_handle ().y (), next.y, out handle_y0, out handle_y1);+		bezier_vector (step, previous.x, previous.get_right_handle ().x, next.get_left_handle ().x, next.x, out handle_x0, out handle_x1);+		bezier_vector (step, previous.y, previous.get_right_handle ().y, next.get_left_handle ().y, next.y, out handle_y0, out handle_y1);  		edit_point.prev = previous_point; 		edit_point.next = next_point;@@ -1486,21 +1432,21 @@ public class Path { 		} 		 		if (right == PointType.DOUBLE_CURVE || left == PointType.DOUBLE_CURVE) {-			all_of_double (start.x, start.y, start.get_right_handle ().x (), start.get_right_handle ().y (), stop.get_left_handle ().x (), stop.get_left_handle ().y (), stop.x, stop.y, iter, steps);+			all_of_double (start.x, start.y, start.get_right_handle ().x, start.get_right_handle ().y, stop.get_left_handle ().x, stop.get_left_handle ().y, stop.x, stop.y, iter, steps); 		} else if (right == PointType.QUADRATIC && left == PointType.QUADRATIC) {-			all_of_quadratic_curve (start.x, start.y, start.get_right_handle ().x (), start.get_right_handle ().y (), stop.x, stop.y, iter, steps);+			all_of_quadratic_curve (start.x, start.y, start.get_right_handle ().x, start.get_right_handle ().y, stop.x, stop.y, iter, steps); 		} else if (right == PointType.CUBIC && left == PointType.CUBIC) {-			all_of_curve (start.x, start.y, start.get_right_handle ().x (), start.get_right_handle ().y (), stop.get_left_handle ().x (), stop.get_left_handle ().y (), stop.x, stop.y, iter, steps);+			all_of_curve (start.x, start.y, start.get_right_handle ().x, start.get_right_handle ().y, stop.get_left_handle ().x, stop.get_left_handle ().y, stop.x, stop.y, iter, steps); 		} else { 			warning (@"Mixed point types in segment $(start.x),$(start.y) to $(stop.x),$(stop.y)");-			all_of_quadratic_curve (start.x, start.y, start.get_right_handle ().x (), start.get_right_handle ().y (), stop.x, stop.y, iter, steps);+			all_of_quadratic_curve (start.x, start.y, start.get_right_handle ().x, start.get_right_handle ().x, stop.x, stop.y, iter, steps); 		} 	}  	public static void get_point_for_step (EditPoint start, EditPoint stop, double step, out double x, out double y) { 		// FIXME: Types-		x = bezier_path (step, start.x, start.get_right_handle ().x (), stop.get_left_handle ().x (), stop.x);-		y = bezier_path (step, start.y, start.get_right_handle ().y (), stop.get_left_handle ().y (), stop.y);	+		x = bezier_path (step, start.x, start.get_right_handle ().x, stop.get_left_handle ().x, stop.x);+		y = bezier_path (step, start.y, start.get_right_handle ().y, stop.get_left_handle ().y, stop.y);	 	}  	private static void all_of_double (double x0, double y0, double x1, double y1, double x2, double y2, double x3, double y3, RasterIterator iter, double steps = 400) {@@ -1956,10 +1902,10 @@ public class Path { 			hl = e.get_left_handle (); 			hr = e.get_right_handle (); 			-			lx = hl.x ();-			ly = hl.y ();-			rx = hr.x ();-			ry = hr.y ();+			lx = hl.x;+			ly = hl.y;+			rx = hr.x;+			ry = hr.y; 						 			e.y *= -1; 			@@ -1977,10 +1923,10 @@ public class Path { 			hl = e.get_left_handle (); 			hr = e.get_right_handle (); 			-			lx = hl.x ();-			ly = hl.y ();-			rx = hr.x ();-			ry = hr.y ();+			lx = hl.x;+			ly = hl.y;+			rx = hr.x;+			ry = hr.y; 						 			e.x *= -1; 			@@ -2041,7 +1987,7 @@ public class Path { 	}  	public static void find_intersection_handle (EditPointHandle h1, EditPointHandle h2, out double point_x, out double point_y) {-		find_intersection (h1.parent.x, h1.parent.y, h1.x (), h1.y (), h2.parent.x, h2.parent.y, h2.x (), h2.y (), out point_x, out point_y);+		find_intersection (h1.parent.x, h1.parent.y, h1.x, h1.y, h2.parent.x, h2.parent.y, h2.x, h2.y, out point_x, out point_y); 	} 	 	public void add_extrema () {diff --git a/libbirdfont/PenTool.vala b/libbirdfont/PenTool.valaindex 14fad88..b0f9600 100644--- a/libbirdfont/PenTool.vala+++ b/libbirdfont/PenTool.vala@@ -394,11 +394,11 @@ public class PenTool : Tool { 			glyph.redraw_area (0, 0, glyph.allocation.width, glyph.allocation.height); 			 			if (GridTool.is_visible ()) {-				last_point_x = Glyph.precise_reverse_path_coordinate_x (selected_handle.x ());-				last_point_y = Glyph.precise_reverse_path_coordinate_y (selected_handle.y ());+				last_point_x = Glyph.precise_reverse_path_coordinate_x (selected_handle.x);+				last_point_y = Glyph.precise_reverse_path_coordinate_y (selected_handle.y); 			} else if (GridTool.has_ttf_grid ()) {-				last_point_x = Glyph.precise_reverse_path_coordinate_x (selected_handle.x ());-				last_point_y = Glyph.precise_reverse_path_coordinate_y (selected_handle.y ());+				last_point_x = Glyph.precise_reverse_path_coordinate_x (selected_handle.x);+				last_point_y = Glyph.precise_reverse_path_coordinate_y (selected_handle.y); 			} else { 				last_point_x = x; 				last_point_y = y;@@ -730,8 +730,8 @@ public class PenTool : Tool { 				 			// 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 (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;@@ -803,7 +803,7 @@ public class PenTool : Tool { 				 				last_rh = last_point.get_right_handle (); 				fist_rh = first_point.get_right_handle ();-				last_rh.move_to_coordinate_internal (last_rh. x (), last_rh.y ());+				last_rh.move_to_coordinate_internal (last_rh. x, last_rh.y); 				 				union.append_path (second_path); 				glyph.add_path (union);diff --git a/libbirdfont/SearchPaths.vala b/libbirdfont/SearchPaths.valaindex fc0b11e..df1380f 100644--- a/libbirdfont/SearchPaths.vala+++ b/libbirdfont/SearchPaths.vala@@ -146,6 +146,10 @@ public class SearchPaths { 		} 		 		f = (!) File.new_for_path ("/usr/share/unicode/ucd/NamesList.txt");+		if (f.query_exists ()) {+			return f;+		}+		 		warning ("ucd not found"); 		 		return f;diff --git a/libbirdfont/Svg.vala b/libbirdfont/Svg.valaindex b7c91cd..ec641da 100644--- a/libbirdfont/Svg.vala+++ b/libbirdfont/Svg.vala@@ -148,8 +148,8 @@ class Svg { 		EditPoint middle; 		double x, y; 		-		x = start.get_right_handle ().x () + (end.get_left_handle ().x () - start.get_right_handle ().x ()) / 2;-		y = start.get_right_handle ().y () + (end.get_left_handle ().y () - start.get_right_handle ().y ()) / 2;+		x = start.get_right_handle ().x + (end.get_left_handle ().x - start.get_right_handle ().x) / 2;+		y = start.get_right_handle ().y + (end.get_left_handle ().y - start.get_right_handle ().y) / 2; 		 		middle = new EditPoint (x, y, PointType.QUADRATIC); 		middle.right_handle = end.get_left_handle ().copy ();diff --git a/libbirdfont/SvgParser.vala b/libbirdfont/SvgParser.valaindex f7f9554..b0a87ff 100644--- a/libbirdfont/SvgParser.vala+++ b/libbirdfont/SvgParser.vala@@ -59,12 +59,12 @@ public class SvgParser { 		TextReader tr;  		foreach (string l in lines) {-			if (l.index_of ("<!--") > -1 && l.index_of ("Illustrator") > -1) {+			if (l.index_of ("Illustrator") > -1 || l.index_of ("illustrator") > -1) { 				parser.set_format (SvgFormat.ILLUSTRATOR); 				has_format = true; 			} 			-			if (l.index_of ("<!--") > -1 && l.index_of ("Inkscape") > -1) {+			if (l.index_of ("Inkscape") > -1 || l.index_of ("inkscape") > -1) { 				parser.set_format (SvgFormat.INKSCAPE); 				has_format = true; 			}	@@ -82,7 +82,7 @@ public class SvgParser { 		xml_document = sb.str;  		if (!has_format) {-			warning ("No format identifier found.");+			stderr.printf ("No format identifier found.\n"); 		}  		Parser.init ();@@ -149,23 +149,189 @@ public class SvgParser { 	} 	 	private void parse_layer (Xml.Node* node, PathList pl) {+		string attr_name = "";+		string attr_content;+		PathList layer = new PathList ();+		 		return_if_fail (node != null);-				+					 		for (Xml.Node* iter = node->children; iter != null; iter = iter->next) { 			if (iter->name == "path") {-				parse_path (iter, pl);+				parse_path (iter, layer); 			} 			 			if (iter->name == "g") {-				parse_layer (iter, pl);+				parse_layer (iter, layer); 			} 			 			if (iter->name == "polygon") {-				parse_polygon (iter, pl);+				parse_polygon (iter, layer); 			} 		}++		for (Xml.Attr* prop = node->properties; prop != null; prop = prop->next) {+			attr_name = prop->name;+			attr_content = prop->children->content;+			+			if (attr_name == "transform") {+				transform (attr_content, layer);+			}+		}+		+		pl.append (layer); 	} 	+	private void transform (string transform_functions, PathList pl) {+		string data = transform_functions.dup ();+		string[] functions;+		+		// use only a single space as separator+		while (data.index_of ("  ") > -1) {+			data = data.replace ("  ", " ");+		}+		+		return_if_fail (data.index_of (")") > -1);+		+		 // add separator+		data = data.replace (") ", "|");+		data = data.replace (")", "|"); +		functions = data.split ("|");+		+		for (int i = 0; i < functions.length; i++) {+			if (functions[i].has_prefix ("translate")) {+				translate (functions[i], pl);+			}+			+			if (functions[i].has_prefix ("scale")) {+				scale (functions[i], pl);+			}++			if (functions[i].has_prefix ("matrix")) {+				matrix (functions[i], pl);+			}+			// TODO: rotate etc.+		}+	}++	public void apply_matrix (Path path, double a, double b, double c, +		double d, double e, double f){+		+		double dx, dy;+		Font font = BirdFont.get_current_font ();+		Glyph glyph = MainWindow.get_current_glyph ();+		+		foreach (EditPoint ep in path.points) {+			apply_matrix_on_handle (ep.get_right_handle (), a, b, c, d, e, f);+			apply_matrix_on_handle (ep.get_left_handle (), a, b, c, d, e, f);++			ep.independent_y = font.top_position - ep.independent_y;+			ep.independent_x -= glyph.left_limit;+			+			dx = a * ep.independent_x + c * ep.independent_y + e;+			dy = b * ep.independent_x + d * ep.independent_y + f;+			+			ep.independent_x = dx;+			ep.independent_y = dy;+			+			ep.independent_y = font.top_position - ep.independent_y;+			ep.independent_x += glyph.left_limit;+		}+	}++	public void apply_matrix_on_handle (EditPointHandle h, +		double a, double b, double c, +		double d, double e, double f){+		+		double dx, dy;+		Font font = BirdFont.get_current_font ();+		Glyph glyph = MainWindow.get_current_glyph ();++		h.y = font.top_position - h.y;+		h.x -= glyph.left_limit;+		+		dx = a * h.x + c * h.y + e;+		dy = b * h.x + d * h.y + f;+		+		h.x = dx;+		h.y = dy;+		+		h.y = font.top_position - h.y;+		h.x += glyph.left_limit;+	}+++	private void matrix (string function, PathList pl) {+		string parameters = get_transform_parameters (function);+		string[] p = parameters.split (" ");++		if (p.length != 6) {+			warning ("Expecting six parameters for matrix transformation.");+			return;+		}++		foreach (Path path in pl.paths) {+			apply_matrix (path, parse_double (p[0]), parse_double (p[1]), +				parse_double (p[2]), parse_double (p[3]), +				parse_double (p[4]), parse_double (p[5]));+		}+	}+		+	private void scale (string function, PathList pl) {+		string parameters = get_transform_parameters (function);+		string[] p = parameters.split (" ");+		double x, y;+		+		x = 1;+		y = 1;+		+		if (p.length > 0) {+			x = parse_double (p[0]);+		}+		+		if (p.length > 1) {+			y = parse_double (p[1]);+		}+		+		foreach (Path path in pl.paths) {+			path.scale (-x, y);+		}+	}+		+	private void translate (string function, PathList pl) {+		string parameters = get_transform_parameters (function);+		string[] p = parameters.split (" ");+		double x, y;+		+		x = 0;+		y = 0;+		+		if (p.length > 0) {+			x = parse_double (p[0]);+		}+		+		if (p.length > 1) {+			y = parse_double (p[1]);+		}+		+		foreach (Path path in pl.paths) {+			path.move (-x, y);+		}+	}++	private string get_transform_parameters (string function) {+		int i;+		string param = "";+		+		i = function.index_of ("(");+		return_val_if_fail (i != -1, param);+		param = function.substring (i);++		param = param.replace ("(", "");+		param = param.replace (",", " ");+				+		return param;			+	}+		 	private void parse_polygon (Xml.Node* node, PathList pl) { 		string attr_name = ""; 		string attr_content;@@ -827,7 +993,6 @@ public class SvgParser {  			// move all points 			if (svg_glyph) {-				// move only y  				b[i].x0 += glyph.left_limit; 				b[i].y0 += font.base_line; 				b[i].x1 += glyph.left_limit;diff --git a/libbirdfont/TestCases.vala b/libbirdfont/TestCases.valaindex 6d5f327..1d1b079 100644--- a/libbirdfont/TestCases.vala+++ b/libbirdfont/TestCases.vala@@ -46,7 +46,8 @@ class TestCases { 		add (test_extrema, "Extrema"); 		add (test_codepages, "Codepages"); 		add (test_double_quadratic, "Double quadratic");-			+		add (test_raster_path, "Raster path");+		 		add_bechmark (benchmark_stroke, "Stroke"); 	} 	@@ -1243,6 +1244,30 @@ class TestCases { 	private static void test_boundaries () { 		Preferences.draw_boundaries = true; 	}+	+	private static void test_raster_path () {+		Glyph g = MainWindow.get_current_glyph ();+		PathList pl = new PathList ();+		Path path;+		+		test_open_next_glyph ();+		test_inkscape_import (); // draw somee thing+		+		foreach (Path p in g.path_list) {+			path = new Path ();+			p.all_of_path ((cx, cy, ct) => {+				path.add (cx, cy);+				return true;+			});+			pl.add (path);+		}+		+		test_open_next_glyph ();+		+		foreach (Path p in pl.paths) {+			g.add_path (p);+		}+	} }  }

Contact

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