The Birdfont Source Code


All Repositories / birdfont.git / commit – RSS feed

Fix resize tool

These changes was commited to the Birdfont repository Mon, 22 Jul 2019 19:21:59 +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>
Mon, 22 Jul 2019 19:21:59 +0000 (21:21 +0200)
committer Johan Mattsson <johan.mattsson.m@gmail.com>
Mon, 22 Jul 2019 19:31:40 +0000 (21:31 +0200)
commit 647f9849000576c6787fd644280d5566311badcf
tree 7f36bb131be85d1a87e20f2e030f0317b5d4a35e
parent 80e179bd4f9883685bc4dea7cb8316df5657f261
Fix resize tool

libbirdfont/Doubles.vala [new ]
libbirdfont/Path.vala
libbirdfont/ResizeTool.vala
libbirdfont/SvgTransform.vala [new ]
libbirdfont/SvgTransforms.vala [new ]
diff --git libbirdfont/Doubles.vala(new)
--- /dev/null +++ b/libbirdfont/Doubles.vala @@ -1,1 +1,175 @@ + /* + Copyright (C) 2015 2019 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. + */ + + using Cairo; + + namespace BirdFont { + + public class Doubles : GLib.Object { + public double* data; + public int size = 0; + int capacity = 10; + + public Doubles () { + data = new double[capacity]; + } + + public Doubles.for_capacity (int capacity) { + data = new double[capacity]; + this.capacity = capacity; + } + + ~Doubles () { + delete data; + data = null; + } + + public void clear () { + size = 0; + } + + public void set_double (int index, double p) { + if (unlikely (index < 0)) { + warning ("index < 0"); + return; + } + + if (unlikely (index >= size)) { + warning ("index >= size"); + return; + } + + data[index] = p; + } + + public void insert (int index, double p) { + insert_element (index); + data[index] = p; + } + + public void insert_element (int index) { + if (capacity < size + 1) { + increase_capacity (); + } + + if (unlikely (index < 0 || index > size)) { + warning (@"Bad index $index."); + return; + } + + double* point_data = new double[capacity]; + + if (index > 0) { + Posix.memcpy (point_data, data, sizeof (double) * index); + } + + if (index < size) { + int dest_position = index + 1; + Posix.memcpy (point_data + dest_position, data + index, sizeof (double) * (size - index)); + } + + size += 1; + delete data; + data = point_data; + } + + public void remove_first (int n) { + if (size < n) { + return; + } + + size -= n; + + for (int i = 0; i < size; i++) { + data[i] = data[i + n]; + } + } + + public void remove (int offset, int length) { + if (unlikely (offset < 0 || offset + length > size)) { + warning (@"Invalid offset: $offset, length: $length, size: $size"); + return; + } + + for (int i = offset; i < size; i++) { + data[i] = data[i + length]; + } + + size -= length; + } + + void increase_capacity () { + int new_capacity = 2 * capacity; + double* new_data = new double[new_capacity]; + Posix.memcpy (new_data, data, sizeof (double) * size); + delete data; + data = new_data; + capacity = new_capacity; + } + + public void add (double d) { + if (size >= capacity) { + increase_capacity (); + } + + data[size] = d; + size++; + } + + public Doubles copy () { + Doubles d = new Doubles (); + delete d.data; + d.data = new double[capacity]; + d.capacity = capacity; + d.size = size; + Posix.memcpy (d.data, data, sizeof (double) * size); + return d; + } + + public double get_double (int index) { + if (unlikely (index < 0)) { + warning ("index < 0"); + return 0; + } + + if (unlikely (index >= size)) { + warning ("index >= size"); + return 0; + } + + return data[index]; + } + + + public string get_string (int i) { + return round (get_double (i)); + } + + public static string round (double p) { + string v = p.to_string (); + char[] c = new char [501]; + + v = p.format (c, "%3.5f"); + + if (v.index_of ("e") != -1) { + return "0.0"; + } + + return v; + } + } + + } +
--- a/libbirdfont/Path.vala +++ b/libbirdfont/Path.vala @@ -1,5 +1,5 @@ /* - Copyright (C) 2012 - 2016 Johan Mattsson + Copyright (C) 2012 - 2016 2019 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 @@ -1147,7 +1147,45 @@ ymin = e.y; } } + + public void transform (Matrix matrix) { + double x, y; + EditPointHandle handle; + foreach (EditPoint point in points) { + x = point.x; + y = point.y; + + matrix.transform_point (ref x, ref y); + + point.independent_x = x; + point.independent_y = y; + + handle = point.get_right_handle (); + + x = handle.x; + y = handle.y; + + matrix.transform_point (ref x, ref y); + + handle.independent_x = x; + handle.independent_y = y; + + handle = point.get_left_handle (); + + x = handle.x; + y = handle.y; + + matrix.transform_point (ref x, ref y); + + handle.independent_x = x; + handle.independent_y = y; + + } + + update_region_boundaries (); + } + /** Test if @param path is a valid outline for this object. */ public bool test_is_outline (Path path) { assert (false);
--- a/libbirdfont/ResizeTool.vala +++ b/libbirdfont/ResizeTool.vala @@ -1,5 +1,5 @@ /* - Copyright (C) 2013 2015 Johan Mattsson + Copyright (C) 2013 2015 2019 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 @@ -351,15 +351,16 @@ public void resize_selected_paths (double ratio_x, double ratio_y) { Glyph g = MainWindow.get_current_glyph (); - resize_glyph (g, ratio_x, ratio_y, true); + resize_glyph (g, ratio_x, ratio_y, true, true); } - - public void resize_glyph (Glyph glyph, double ratio_x, - double ratio_y, bool selected = true) { - - double resize_pos_x = 0; - double resize_pos_y = 0; - double selection_minx, selection_miny, dx, dy; + + public void resize_glyph (Glyph glyph, + double ratio_x, + double ratio_y, + bool selected = true, + bool relative_to_object = false) { + + Font font = BirdFont.get_current_font (); if (!selected) { glyph.clear_active_paths (); @@ -369,25 +370,38 @@ } } - get_selection_min (out resize_pos_x, out resize_pos_y); - - // resize paths - foreach (Path selected_path in glyph.active_paths) { - selected_path.resize (ratio_x, ratio_y); - selected_path.reset_stroke (); + foreach (Path path in glyph.active_paths) { + x = selection_box_center_x - selection_box_width / 2; + y = font.base_line; + + if (relative_to_object) { + y = selection_box_center_y - selection_box_height / 2; + } + + SvgTransforms transform = new SvgTransforms (); + transform.resize (ratio_x, ratio_y, x, y); + Matrix matrix = transform.get_matrix (); + path.transform (matrix); + path.reset_stroke (); } - + if (glyph.active_paths.size > 0) { - update_selection_box (); - objects_resized (selection_box_width, selection_box_height); + foreach (Path p in glyph.active_paths) { + p.update_region_boundaries (); + } } if (!selected) { - glyph.left_limit *= ratio_x; + glyph.add_help_lines (); + glyph.left_limit *= ratio_x; glyph.right_limit *= ratio_x; glyph.clear_active_paths (); glyph.remove_lines (); glyph.add_help_lines (); + + glyph.view_zoom = 1; + glyph.view_offset_x = 0; + glyph.view_offset_y = 0; } }
--- /dev/null +++ b/libbirdfont/SvgTransform.vala @@ -1,1 +1,113 @@ + /* + Copyright (C) 2016 2019 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. + */ + + using B; + using Cairo; + + namespace BirdFont { + + public enum TransformType { + NONE, + TRANSLATE, + MATRIX, + SCALE, + ROTATE + } + + public class SvgTransform : GLib.Object { + public TransformType type = TransformType.NONE; + public Doubles arguments = new Doubles.for_capacity (10); + + 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; + transform.arguments = arguments.copy (); + return transform; + } + + public string to_string () { + StringBuilder sb = new StringBuilder (); + + sb.append (@"$type"); + sb.append (" "); + + for (int i = 0; i < arguments.size; i++) { + sb.append (@"$(arguments.get_double (i)) "); + } + + return sb.str; + } + + public Matrix get_matrix () { + Matrix matrix; + + matrix = Matrix.identity (); + + if (type == TransformType.ROTATE) { + if (arguments.size == 1) { + double r = arguments.get_double (0); + r *= Math.PI / 180; + matrix.rotate (r); + } + } else if (type == TransformType.SCALE) { + if (arguments.size == 1) { + double s = arguments.get_double (0); + matrix.scale (s, s); + } else if (arguments.size == 2) { + double s0 = arguments.get_double (0); + double s1 = arguments.get_double (1); + matrix.scale (s0, s1); + } + } else if (type == TransformType.TRANSLATE) { + if (arguments.size == 1) { + double s = arguments.get_double (0); + matrix.translate (s, 0); + } else if (arguments.size == 2) { + double s0 = arguments.get_double (0); + double s1 = arguments.get_double (1); + matrix.translate (s0, s1); + } + } else if (type == TransformType.MATRIX) { + if (arguments.size == 6) { + double s0 = arguments.get_double (0); + double s1 = arguments.get_double (1); + double s2 = arguments.get_double (2); + double s3 = arguments.get_double (3); + double s4 = arguments.get_double (4); + double s5 = arguments.get_double (5); + + matrix = Matrix (s0, s1, s2, s3, s4, s5); + } + } + + return matrix; + } + } + + }
--- /dev/null +++ b/libbirdfont/SvgTransforms.vala @@ -1,1 +1,175 @@ + /* + Copyright (C) 2016 2019 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. + */ + + using Cairo; + + namespace BirdFont { + + public class SvgTransforms : GLib.Object { + public Matrix rotation_matrix; + public Matrix size_matrix; + public Gee.ArrayList<SvgTransform> transforms; + + public double rotation = 0; + public double total_rotation = 0; + public double translate_x = 0; + public double translate_y = 0; + + public SvgTransforms () { + transforms = new Gee.ArrayList<SvgTransform> (); + rotation_matrix = Matrix.identity (); + size_matrix = Matrix.identity (); + } + + public void clear_rotation () { + rotation = 0; + total_rotation = 0; + rotation_matrix = Matrix.identity (); + } + + public double get_rotation () { + Matrix m = get_matrix (); + double w = 1; + double h = 1; + m.transform_distance (ref w, ref h); + return Math.atan2 (h, w); + } + + public void collapse_transforms () { + Matrix collapsed = get_matrix (); + + translate_x = 0; + translate_y = 0; + + rotation_matrix = Matrix.identity (); + rotation = 0; + + size_matrix = Matrix.identity (); + + clear (); + + SvgTransform collapsed_transform = new SvgTransform.for_matrix (collapsed); + add (collapsed_transform); + } + + public void clear () { + transforms.clear (); + + rotation_matrix = Matrix.identity (); + rotation = 0; + + size_matrix = Matrix.identity (); + + translate_x = 0; + translate_y = 0; + } + + public void translate (double x, double y) { + translate_x += x; + translate_y += y; + } + + public void rotate (double theta, double x, double y) { + rotation += theta; + total_rotation += theta; + + while (rotation > 2 * Math.PI) { + rotation -= 2 * Math.PI; + } + + while (rotation < -2 * Math.PI) { + rotation += 2 * Math.PI; + } + + while (total_rotation > 2 * Math.PI) { + total_rotation -= 2 * Math.PI; + } + + while (total_rotation < -2 * Math.PI) { + total_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 scale_x, double scale_y, double x, double y) { + if (scale_x <= 0 || scale_y <= 0) { + return; + } + + double x2 = x; + double y2 = y; + + size_matrix = Matrix.identity (); + size_matrix.scale (scale_x, scale_y); + size_matrix.transform_point (ref x2, ref y2); + + double dx = x - x2; + double dy = y - y2; + + size_matrix.translate (dx / scale_x, dy / scale_y); + } + + public SvgTransforms copy () { + SvgTransforms copy_transforms = new SvgTransforms (); + + foreach (SvgTransform t in transforms) { + copy_transforms.add (t.copy ()); + } + + return copy_transforms; + } + + public void insert (int position, SvgTransform transform) { + transforms.insert (position, transform); + } + + public void add (SvgTransform transform) { + transforms.add (transform); + } + + public Matrix get_matrix () { + Matrix transformation_matrix = Matrix.identity (); + + for (int i = 0; i < transforms.size; i++) { + Matrix part = transforms.get (i).get_matrix (); + transformation_matrix.multiply (part, transformation_matrix); + } + + transformation_matrix.translate (translate_x, translate_y); + + transformation_matrix.multiply (transformation_matrix, rotation_matrix); + transformation_matrix.multiply (transformation_matrix, size_matrix); + + return transformation_matrix; + } + + public string to_string () { + StringBuilder sb = new StringBuilder (); + + foreach (SvgTransform t in transforms) { + sb.append (t.to_string ()); + sb.append (" "); + } + + return sb.str; + } + } + + } +