Commit e380d78
Rotate SVG paths
Changed files (22)
modifiedlibbirdfont/DrawingTools.valamodifiedlibbirdfont/EmbeddedSvg.valamodifiedlibbirdfont/Glyph.valamodifiedlibbirdfont/MoveTool.valamodifiedlibbirdfont/OverView.valamodifiedlibbirdfont/PathObject.valamodifiedlibbirdfont/PenTool.valamodifiedlibbirdfont/ResizeTool.valamodifiedlibsvgbird/Circle.valamodifiedlibsvgbird/Ellipse.valamodifiedlibsvgbird/EmptyObject.valamodifiedlibsvgbird/Layer.valamodifiedlibsvgbird/Line.valamodifiedlibsvgbird/Object.valamodifiedlibsvgbird/Polygon.valamodifiedlibsvgbird/Polyline.valamodifiedlibsvgbird/Rectangle.valamodifiedlibsvgbird/SvgDrawing.valamodifiedlibsvgbird/SvgPath.valamodifiedlibsvgbird/SvgStyle.valamodifiedlibsvgbird/SvgTransform.valamodifiedlibsvgbird/SvgTransforms.vala
Diff
@@ -390,7 +390,7 @@ public class DrawingTools : ToolCollection { if (glyph.active_paths.size > 0) { last_path = glyph.active_paths.get (glyph.active_paths.size - 1);- resize_tool.rotate_selected_paths (angle - last_path.rotation, x, y); + resize_tool.rotate_selected_paths (angle - last_path.transforms.rotation, x, y); } GlyphCanvas.redraw ();@@ -805,12 +805,12 @@ public class DrawingTools : ToolCollection { if (StrokeTool.add_stroke) { foreach (SvgBird.Object p in g.active_paths) {- p.stroke = StrokeTool.stroke_width;- p.line_cap = StrokeTool.line_cap;+ p.style.stroke_width = StrokeTool.stroke_width;+ p.style.line_cap = StrokeTool.line_cap; } } else { foreach (SvgBird.Object p in g.active_paths) {- p.stroke = 0;+ p.style.stroke_width = 0; } } @@ -845,7 +845,7 @@ public class DrawingTools : ToolCollection { if (tool && StrokeTool.add_stroke) { foreach (SvgBird.Object p in g.active_paths) {- p.stroke = StrokeTool.stroke_width;+ p.style.stroke_width = StrokeTool.stroke_width; if (p is PathObject) { Path path = ((PathObject) p).get_path ();@@ -887,7 +887,7 @@ public class DrawingTools : ToolCollection { g.store_undo_state (); foreach (SvgBird.Object p in g.active_paths) {- p.line_cap = SvgBird.LineCap.BUTT;+ p.style.line_cap = SvgBird.LineCap.BUTT; if (p is PathObject) { ((PathObject) p).get_path ().reset_stroke ();@@ -914,7 +914,7 @@ public class DrawingTools : ToolCollection { g.store_undo_state (); foreach (SvgBird.Object p in g.active_paths) {- p.line_cap = SvgBird.LineCap.ROUND;+ p.style.line_cap = SvgBird.LineCap.ROUND; if (p is PathObject) { ((PathObject) p).get_path ().reset_stroke ();@@ -942,7 +942,7 @@ public class DrawingTools : ToolCollection { g.store_undo_state (); foreach (SvgBird.Object p in g.active_paths) {- p.line_cap = SvgBird.LineCap.SQUARE;+ p.style.line_cap = SvgBird.LineCap.SQUARE; if (p is PathObject) { ((PathObject) p).get_path ().reset_stroke ();@@ -1277,7 +1277,7 @@ public class DrawingTools : ToolCollection { Glyph g = MainWindow.get_current_glyph (); foreach (SvgBird.Object p in g.active_paths) {- if (p.stroke > 0) {+ if (p.style.stroke_width > 0) { stroke = true; } }@@ -49,12 +49,12 @@ public class EmbeddedSvg : SvgBird.Object { public void draw_embedded_svg (Context cr) { cr.save (); cr.translate (Glyph.xc () + x, Glyph.yc () - y);+ apply_transform (cr); drawing.draw (cr); cr.restore (); } public override void draw_outline (Context cr) {- cr.translate (x, -y); drawing.draw_outline (cr); } @@ -64,18 +64,10 @@ public class EmbeddedSvg : SvgBird.Object { move_bounding_box (dx, -dy); } - public override void rotate (double theta, double xc, double yc) {- drawing.rotate (theta, xc, yc);- }- public override bool is_empty () { return drawing.is_empty (); } - public override void resize (double ratio_x, double ratio_y) {- drawing.resize (ratio_x, ratio_y);- }- public override SvgBird.Object copy () { EmbeddedSvg svg = new EmbeddedSvg ((SvgDrawing) drawing.copy ()); SvgBird.Object.copy_attributes (this, svg);@@ -1527,7 +1527,7 @@ public class Glyph : FontDisplay { if (!draw_control_points) { foreach (SvgBird.Object object in get_visible_objects ()) { if (object is PathObject- && object.stroke > 0) {+ && object.style.stroke_width > 0) { has_path = true; PathObject object_path = (PathObject) object; @@ -1547,7 +1547,7 @@ public class Glyph : FontDisplay { if (!draw_control_points) { foreach (SvgBird.Object object in get_visible_objects ()) { if (object is PathObject- && object.stroke == 0) {+ && object.style.stroke_width == 0) { has_path = true; PathObject object_path = (PathObject) object; @@ -29,10 +29,12 @@ public class MoveTool : Tool { static double selection_y = 0; static bool group_selection= false; - public static static double selection_box_width = 0;- public static static double selection_box_height = 0;- public static static double selection_box_center_x = 0;- public static static double selection_box_center_y = 0;+ public static double selection_box_width = 0;+ public static double selection_box_height = 0;+ public static double selection_box_center_x = 0;+ public static double selection_box_center_y = 0;+ public static double selection_box_left = 0;+ public static double selection_box_top = 0; public signal void selection_changed (); public signal void objects_moved ();@@ -249,15 +251,16 @@ public class MoveTool : Tool { public static void update_selection_boundaries () { get_selection_box_boundaries (out selection_box_center_x, out selection_box_center_y, out selection_box_width,- out selection_box_height); + out selection_box_height, out selection_box_left, + out selection_box_top); } public void move_to_baseline () { Glyph glyph = MainWindow.get_current_glyph (); Font font = BirdFont.get_current_font ();- double x, y, w, h;+ double x, y, w, h, l, t; - get_selection_box_boundaries (out x, out y, out w, out h);+ get_selection_box_boundaries (out x, out y, out w, out h, out l, out t); foreach (SvgBird.Object path in glyph.active_paths) { path.move (glyph.left_limit - x + w / 2, font.base_line - y + h / 2);@@ -268,7 +271,9 @@ public class MoveTool : Tool { GlyphCanvas.redraw (); } - public static void get_selection_box_boundaries (out double x, out double y, out double w, out double h) {+ public static void get_selection_box_boundaries (out double x, out double y, out double w, out double h,+ out double left, out double top) {+ double px, py, px2, py2; Glyph glyph = MainWindow.get_current_glyph (); @@ -276,6 +281,8 @@ public class MoveTool : Tool { py = 10000; px2 = -10000; py2 = -10000;+ top = 10000;+ left = 10000; foreach (SvgBird.Object o in glyph.active_paths) { if (o is PathObject) {@@ -283,6 +290,14 @@ public class MoveTool : Tool { p.update_region_boundaries (); } + if (top > o.top) {+ top = o.top;+ }++ if (left > o.left) {+ left = o.left;+ }+ if (px > o.xmin) { px = o.xmin; } @@ -410,11 +425,7 @@ public class MoveTool : Tool { public static void update_boundaries_for_selection () { Glyph glyph = MainWindow.get_current_glyph ();- foreach (SvgBird.Object o in glyph.active_paths) {- if (o is PathObject) {- ((PathObject)o).get_path ().update_region_boundaries ();- }- }+ glyph.layers.update_boundaries_for_object (); } public static void flip_vertical () {@@ -426,7 +437,7 @@ public class MoveTool : Tool { } public static void flip (bool vertical) {- double xc, yc, xc2, yc2, w, h; + double xc, yc, xc2, yc2, w, h, l, t; double dx, dy; Glyph glyph = MainWindow.get_current_glyph (); @@ -450,7 +461,7 @@ public class MoveTool : Tool { } } - get_selection_box_boundaries (out xc2, out yc2, out w, out h); + get_selection_box_boundaries (out xc2, out yc2, out w, out h, out l, out t); dx = -(xc2 - xc); dy = -(yc2 - yc);@@ -1455,7 +1455,6 @@ public class OverView : FontDisplay { selected_item = get_selected_item (); if (selected_item.glyphs != null) { open_glyph_signal ((!) selected_item.glyphs);- GlyphCollection? gc2 = selected_item.glyphs; GlyphCollection gc = (!) selected_item.glyphs; gc.get_current ().close_path (); } else {@@ -57,7 +57,7 @@ public class PathObject : SvgBird.Object { } } - public override double stroke {+ public double stroke { get { return path.stroke; }@@ -98,11 +98,16 @@ public class PathObject : SvgBird.Object { } public void draw_path (Context cr) {+ cr.save ();+ apply_transform (cr);+ if (path.stroke > 0) { draw_path_list (path.get_completed_stroke (), cr); } else { path.draw_path (cr); }+ + cr.restore (); } public static void draw_path_list (PathList pl, Context cr) {@@ -128,19 +133,10 @@ public class PathObject : SvgBird.Object { return base.update_boundaries (cr); } - public override void rotate (double theta, double xc, double yc) {- path.rotate (theta, xc, yc);- }- public override bool is_empty () { return path.points.size == 0; } - public override void resize (double ratio_x, double ratio_y) {- path.resize (ratio_x, ratio_y);- path.reset_stroke ();- }- public override SvgBird.Object copy () { return new PathObject.create_copy (this); }@@ -1055,11 +1055,14 @@ public class PenTool : Tool { // don't use set point to reflective to on open ends reflective = true; foreach (SvgBird.Object path in MainWindow.get_current_glyph ().active_paths) {- if (path.is_open () && !path.is_empty () && path is PathObject) {+ if (!path.is_empty () && path is PathObject) { Path p = ((PathObject) path).get_path ();- if (selected_handle.parent == p.get_first_point () - || selected_handle.parent == p.get_last_point ()) {- reflective = false;+ + if (p.is_open ()) { + if (selected_handle.parent == p.get_first_point () + || selected_handle.parent == p.get_last_point ()) {+ reflective = false;+ } } } }@@ -1835,8 +1838,6 @@ public class PenTool : Tool { Glyph g = MainWindow.get_current_glyph (); PathObject path; - print ("Insert\n");- if (!g.has_active_path_objects ()) { np = new Path (); g.add_path (np);@@ -1,5 +1,5 @@ /*- Copyright (C) 2013 2015 Johan Mattsson+ Copyright (C) 2013 2015 2016 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 @@ -32,7 +32,9 @@ public class ResizeTool : Tool { static double selection_box_height = 0; static double selection_box_center_x = 0; static double selection_box_center_y = 0;-+ static double selection_box_left = 0;+ static double selection_box_top = 0;+ static bool rotate_path = false; static double last_rotate_y; static double rotation = 0;@@ -97,7 +99,7 @@ public class ResizeTool : Tool { if (glyph.active_paths.size > 0) { last_path = glyph.active_paths.get (glyph.active_paths.size - 1);- last_rotate = last_path.rotation;+ last_rotate = last_path.transforms.rotation; } rotation = last_rotate;@@ -127,7 +129,9 @@ public class ResizeTool : Tool { PathObject path = (PathObject) p; path.get_path ().create_full_stroke (); }- }+ + p.transforms.collapse_transforms ();+ } }); move_action.connect ((self, x, y) => {@@ -145,7 +149,6 @@ public class ResizeTool : Tool { if (rotate_path) { rotate (x, y);- update_selection_box (); } if (move_paths @@ -235,26 +238,26 @@ public class ResizeTool : Tool { public void rotate_selected_paths (double angle, double cx, double cy) { Glyph glyph = MainWindow.get_current_glyph (); - double dx, dy, xc2, yc2, w, h; SvgBird.Object last_path;+ double x, y; - foreach (SvgBird.Object p in glyph.active_paths) {- p.rotate (angle, cx, cy);- }-- MoveTool.get_selection_box_boundaries (out xc2, out yc2, out w, out h); -- dx = -(xc2 - cx);- dy = -(yc2 - cy);+ glyph.layers.update_boundaries_for_object (); foreach (SvgBird.Object p in glyph.active_paths) {- p.move (dx, dy);+ if (p is EmbeddedSvg) {+ EmbeddedSvg svg = (EmbeddedSvg) p;+ x = selection_box_left - svg.x + selection_box_width / 2;+ y = selection_box_top + svg.y + selection_box_height / 2;+ p.transforms.rotate (angle, x, y);+ } else {+ x = selection_box_left + selection_box_width / 2;+ y = selection_box_top + selection_box_height / 2;+ p.transforms.rotate (angle, x, y);+ } }- + last_rotate = rotation;- - MoveTool.update_selection_boundaries ();- + if (glyph.active_paths.size > 0) { last_path = glyph.active_paths.get (glyph.active_paths.size - 1); @@ -272,20 +275,15 @@ public class ResizeTool : Tool { /** Move rotate handle to pixel x,y. */ void rotate (double x, double y) {- double cx, cy, xc, yc, a, b; - - cx = Glyph.reverse_path_coordinate_x (selection_box_center_x);- cy = Glyph.reverse_path_coordinate_y (selection_box_center_y);- xc = selection_box_center_x;- yc = selection_box_center_y;- - a = x - cx;- b = y - cy;+ double a, b; - rotation = atan (b / a);+ a = Glyph.path_coordinate_x (x) - selection_box_center_x;+ b = selection_box_center_y - Glyph.path_coordinate_y (y); - if (a < 0) {- rotation += PI;+ rotation = atan2 (b, a);++ if (a == 0) {+ rotation = b > 0 ? PI / 2 : -PI / 2; } rotate_selected_paths (rotation - last_rotate, selection_box_center_x, selection_box_center_y);@@ -377,7 +375,7 @@ public class ResizeTool : Tool { // resize paths foreach (SvgBird.Object selected_path in glyph.active_paths) {- selected_path.resize (ratio_x, ratio_y);+ selected_path.transforms.resize (ratio_x, ratio_y); } // move paths relative to the updated xmin and xmax@@ -388,7 +386,7 @@ public class ResizeTool : Tool { foreach (SvgBird.Object selected_path in glyph.active_paths) { selected_path.move (dx, dy); }- + if (glyph.active_paths.size > 0) { update_selection_box (); objects_resized (selection_box_width, selection_box_height);@@ -409,7 +407,7 @@ public class ResizeTool : Tool { MoveTool.update_boundaries_for_selection (); MoveTool.get_selection_box_boundaries (out selection_box_center_x, out selection_box_center_y, out selection_box_width,- out selection_box_height);+ out selection_box_height, out selection_box_left, out selection_box_top); } /** Move resize handle to pixel x,y. */@@ -441,44 +439,6 @@ public class ResizeTool : Tool { last_resize_y = py; } }- - public void full_height () {- double xc, yc, w, h;- Glyph glyph = MainWindow.get_current_glyph ();- Font font = BirdFont.get_current_font ();- - MoveTool.update_boundaries_for_selection ();- MoveTool.get_selection_box_boundaries (out xc, out yc, out w, out h);-- //compute scale- double descender = font.base_line - (yc - h / 2);- - if (descender < 0) {- descender = 0;- }- - double font_height = font.top_position - font.base_line;- double scale = font_height / (h - descender);- - resize_selected_paths (scale, scale);- PenTool.reset_stroke ();-- MoveTool.update_boundaries_for_selection ();- font.touch ();-- MoveTool.get_selection_box_boundaries (out selection_box_center_x,- out selection_box_center_y,- out selection_box_width,- out selection_box_height);- - DrawingTools.move_tool.move_to_baseline ();-- foreach (SvgBird.Object path in glyph.active_paths) {- path.move (0, -descender * scale);- }- - objects_resized (selection_box_width, selection_box_height);- } void get_selection_min (out double x, out double y) { Glyph glyph = MainWindow.get_current_glyph ();@@ -37,16 +37,10 @@ public class Circle : Object { public override void move (double dx, double dy) { } - public override void rotate (double theta, double xc, double yc) {- }- public override bool is_empty () { return false; } - public override void resize (double ratio_x, double ratio_y) {- }- public override Object copy () { Circle c = new Circle (); @@ -43,16 +43,10 @@ public class Ellipse : Object { public override void move (double dx, double dy) { } - public override void rotate (double theta, double xc, double yc) {- }- public override bool is_empty () { return false; } - public override void resize (double ratio_x, double ratio_y) {- }- public override Object copy () { Ellipse e = new Ellipse (); Object.copy_attributes (this, e);@@ -30,17 +30,11 @@ public class EmptyObject : Object { public override void move (double dx, double dy) { }- - public override void rotate (double theta, double xc, double yc) {- }- + public override bool is_empty () { return false; }- - public override void resize (double ratio_x, double ratio_y) {- }- + public override Object copy () { return new EmptyObject (); }@@ -224,17 +224,11 @@ public class Layer : Object { public override void move (double dx, double dy) { }-- public override void rotate (double theta, double xc, double yc) {- } public override bool is_empty () { return false; } - public override void resize (double ratio_x, double ratio_y) {- }- public override string to_string () { return "Layer: " + name; }@@ -46,17 +46,11 @@ public class Line : Object { public override void move (double dx, double dy) { }- - public override void rotate (double theta, double xc, double yc) {- }- + public override bool is_empty () { return false; } - public override void resize (double ratio_x, double ratio_y) {- }- public override Object copy () { return new Line.create_copy (this); }@@ -18,8 +18,6 @@ using Math; namespace SvgBird { public abstract class Object : GLib.Object {- bool open = false;- public bool visible = true; public SvgStyle style = new SvgStyle (); public SvgTransforms transforms = new SvgTransforms ();@@ -27,10 +25,6 @@ public abstract class Object : GLib.Object { public string id = ""; public string css_class = ""; - public virtual Color? color { get; set; } // FIXME: keep this in svg style- public virtual Color? stroke_color { get; set; }- public virtual Gradient? gradient { get; set; }- /** Path boundaries */ public virtual double left { get; set; } public virtual double right { get; set; }@@ -90,12 +84,6 @@ public abstract class Object : GLib.Object { } } - // FIXME: DELETE- public virtual double rotation { get; set; }- public virtual double stroke { get; set; }- public virtual LineCap line_cap { get; set; default = LineCap.BUTT; }- public virtual bool fill { get; set; }- public const double CANVAS_MAX = 100000; public const double CANVAS_MIN = -100000; @@ -103,24 +91,13 @@ public abstract class Object : GLib.Object { } public Object.create_copy (Object o) { - open = o.open;- }- - public void set_open (bool open) {- this.open = open; } - public bool is_open () {- return open;- }- public abstract bool is_over (double x, double y); public abstract void draw_outline (Context cr); public abstract Object copy ();- public abstract void rotate (double theta, double xc, double yc); public abstract bool is_empty ();- public abstract void resize (double ratio_x, double ratio_y); public abstract void move (double dx, double dy); public virtual void move_bounding_box (double dx, double dy) {@@ -131,35 +108,10 @@ public abstract class Object : GLib.Object { } public static void copy_attributes (Object from, Object to) {- to.open = from.open;-- if (from.color != null) {- to.color = ((!) from.color).copy ();- } else {- to.color = null;- }- - if (from.stroke_color != null) {- to.stroke_color = ((!) from.stroke_color).copy ();- } else {- to.stroke_color = null;- }- - if (to.gradient != null) {- to.gradient = ((!) from.gradient).copy ();- } else {- to.gradient = null;- }- - to.xmax = from.xmax;- to.xmin = from.xmin;- to.ymax = from.ymax;- to.ymin = from.ymin;- - to.rotation = from.rotation;- to.stroke = from.stroke;- to.line_cap = from.line_cap;- to.fill = from.fill;+ to.left = from.left;+ to.right = from.right;+ to.top = from.top;+ to.bottom = from.bottom; to.style = from.style.copy (); to.transforms = from.transforms.copy ();@@ -244,10 +196,10 @@ public abstract class Object : GLib.Object { Matrix view_matrix = cr.get_matrix (); Matrix object_matrix = transforms.get_matrix (); - object_matrix.multiply (object_matrix, view_matrix);+ object_matrix.multiply (object_matrix, view_matrix); cr.set_matrix (object_matrix); }-+ /** @return true if the object has an area. */ public virtual bool update_boundaries (Context context) { double x0, y0, x1, y1;@@ -276,6 +228,7 @@ public abstract class Object : GLib.Object { return boundaries_width != 0; } + // FIXME: store view matrix public virtual bool update_boundaries_for_object () { ImageSurface surface = new Cairo.ImageSurface (Cairo.Format.ARGB32, 1, 1); Context context = new Cairo.Context (surface);@@ -45,16 +45,10 @@ public class Polygon : Object { public override void move (double dx, double dy) { } - public override void rotate (double theta, double xc, double yc) {- }- public override bool is_empty () { return false; } - public override void resize (double ratio_x, double ratio_y) {- }- public override Object copy () { Polygon p = new Polygon (); p.points = points.copy ();@@ -42,17 +42,11 @@ public class Polyline : Object { public override void move (double dx, double dy) { }-- public override void rotate (double theta, double xc, double yc) {- } public override bool is_empty () { return false; } - public override void resize (double ratio_x, double ratio_y) {- }- public override Object copy () { Polyline p = new Polyline (); p.points = points.copy ();@@ -65,16 +65,10 @@ public class Rectangle : Object { y += dy; } - public override void rotate (double theta, double xc, double yc) {- }- public override bool is_empty () { return false; } - public override void resize (double ratio_x, double ratio_y) {- }- public override Object copy () { Rectangle r = new Rectangle (); @@ -83,17 +83,11 @@ public class SvgDrawing : Object { public override void move (double dx, double dy) { }- - public override void rotate (double theta, double xc, double yc) {- }- + public override bool is_empty () { return false; } - public override void resize (double ratio_x, double ratio_y) {- }- public override string to_string () { return @"SvgDrawing width: $width, height: $height"; }@@ -94,17 +94,11 @@ public class SvgPath : Object { public override void move (double dx, double dy) { }- - public override void rotate (double theta, double xc, double yc) {- }- + public override bool is_empty () { return false; } - public override void resize (double ratio_x, double ratio_y) {- }- public override Object copy () { return new SvgPath.create_copy (this); }@@ -24,6 +24,7 @@ public class SvgStyle : GLib.Object { public Color? fill = null; public Gradient? stroke_gradient = null; public Gradient? fill_gradient = null;+ public LineCap line_cap = LineCap.BUTT; public double stroke_width = 0; @@ -31,6 +31,17 @@ public class SvgTransform : GLib.Object { public SvgTransform () { } + public SvgTransform.for_matrix (Matrix matrix) {+ type = TransformType.MATRIX;++ arguments.add (matrix.xx);+ arguments.add (matrix.yx);+ arguments.add (matrix.xy);+ arguments.add (matrix.yy);+ arguments.add (matrix.x0);+ arguments.add (matrix.y0);+ }+ public SvgTransform copy () { SvgTransform transform = new SvgTransform (); transform.type = type;@@ -17,13 +17,53 @@ using Cairo; namespace SvgBird { public class SvgTransforms : GLib.Object {+ public Matrix rotation_matrix; public Gee.ArrayList<SvgTransform> transforms; public double x = 0; public double y = 0;+ public double rotation = 0;+ public double scale_x = 1;+ public double scale_y = 1; public SvgTransforms () { transforms = new Gee.ArrayList<SvgTransform> ();+ rotation_matrix = Matrix.identity ();+ }++ public void collapse_transforms () {+ SvgTransform transform = new SvgTransform.for_matrix (rotation_matrix);+ add (transform);+ + rotation_matrix = Matrix.identity ();+ rotation = 0;+ + Matrix collapsed = get_matrix ();+ SvgTransform transform_transform = new SvgTransform.for_matrix (collapsed);+ transforms.clear ();+ add (transform_transform);+ }++ public void rotate (double theta, double x, double y) {+ rotation += theta;+ + while (rotation > 2 * Math.PI) {+ rotation -= 2 * Math.PI;+ }++ while (rotation < -2 * Math.PI) {+ rotation += 2 * Math.PI;+ }++ rotation_matrix = Matrix.identity ();+ rotation_matrix.translate (x, y);+ rotation_matrix.rotate (rotation);+ rotation_matrix.translate (-x, -y);+ }++ public void resize (double x, double y) {+ scale_x += x;+ scale_y += y; } public SvgTransforms copy () {@@ -41,24 +81,21 @@ public class SvgTransforms : GLib.Object { } public Matrix get_matrix () {- Matrix matrix = Matrix.identity ();- - matrix.translate (x, y);+ Matrix transformation_matrix = Matrix.identity (); for (int i = 0; i < transforms.size; i++) {- matrix.multiply (matrix, transforms.get (i).get_matrix ());+ Matrix part = transforms.get (i).get_matrix ();+ transformation_matrix.multiply (transformation_matrix, part); }- - return matrix;++ transformation_matrix.multiply (transformation_matrix, rotation_matrix);++ return transformation_matrix; } public string to_string () { StringBuilder sb = new StringBuilder ();- - if (x != 0 || y != 0) {- sb.append (@"$(TransformType.TRANSLATE): $x,$y ");- }- + foreach (SvgTransform t in transforms) { sb.append (t.to_string ()); sb.append (" ");