Commit 647f984
Fix resize tool
Changed files (5)
addedlibbirdfont/Doubles.valamodifiedlibbirdfont/Path.valamodifiedlibbirdfont/ResizeTool.valaaddedlibbirdfont/SvgTransform.valaaddedlibbirdfont/SvgTransforms.vala
Diff
new file mode 100644@@ -0,0 +1,174 @@+/*+ 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;+ }+}++}+@@ -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 @@ public class Path : GLib.Object { 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);@@ -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 class ResizeTool : Tool { 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 @@ public class ResizeTool : Tool { } } - 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; } } new file mode 100644@@ -0,0 +1,112 @@+/*+ 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;+ }+}++}new file mode 100644@@ -0,0 +1,174 @@+/*+ 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;+ }+}++}+