The Birdfont Source Code


All Repositories / birdfont.git / blob – RSS feed

PointConverter.vala in libbirdfont

This file is a part of the Birdfont project.

Contributing

Send patches or pull requests to johan.mattsson.m@gmail.com.
Clone this repository: git clone https://github.com/johanmattssonm/birdfont.git

Revisions

View the latest version of libbirdfont/PointConverter.vala.
Parse more style attributes in SVG files
1 /* 2 Copyright (C) 2014 Johan Mattsson 3 4 This library is free software; you can redistribute it and/or modify 5 it under the terms of the GNU Lesser General Public License as 6 published by the Free Software Foundation; either version 3 of the 7 License, or (at your option) any later version. 8 9 This library is distributed in the hope that it will be useful, but 10 WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 Lesser General Public License for more details. 13 */ 14 15 using Cairo; 16 using Math; 17 18 namespace BirdFont { 19 20 /** A class for converting control points. */ 21 public class PointConverter { 22 23 Path original_path; 24 Path quadratic_path; 25 26 public PointConverter (Path path) { 27 original_path = path; 28 } 29 30 public Path get_quadratic_path () { 31 bool add_more_points = false; 32 33 quadratic_path = original_path.copy (); 34 35 estimated_cubic_path (); 36 37 if (add_more_points) { 38 warning ("Too many points in segment."); 39 } 40 41 if (quadratic_path.points.size < 2) { 42 return new Path (); 43 } 44 45 foreach (EditPoint e in quadratic_path.points) { 46 if (e.get_right_handle ().type == PointType.CUBIC) { 47 PenTool.convert_point_segment_type (e, e.get_next (), PointType.DOUBLE_CURVE); 48 } 49 } 50 51 if (quadratic_path.get_last_point ().get_right_handle ().type == PointType.CUBIC) { 52 PenTool.convert_point_segment_type (quadratic_path.get_last_point (), 53 quadratic_path.get_first_point (), 54 PointType.DOUBLE_CURVE); 55 } 56 57 quadratic_path.add_hidden_double_points (); 58 59 return quadratic_path; 60 } 61 62 public void estimated_cubic_path () { 63 EditPoint segment_start; 64 EditPoint segment_stop; 65 EditPoint quadratic_segment_start; 66 EditPoint quadratic_segment_stop; 67 EditPoint e; 68 double distance, step; 69 int points_in_segment = 0; 70 int size; 71 72 foreach (EditPoint ep in quadratic_path.points) { 73 ep.set_tie_handle (false); 74 ep.set_reflective_handles (false); 75 } 76 77 size = quadratic_path.points.size; 78 segment_start = quadratic_path.get_first_point (); 79 for (int i = 0; i < size; i++) { 80 segment_stop = (i == size -1) 81 ? quadratic_path.get_first_point () 82 : segment_start.get_next (); 83 84 quadratic_segment_start = segment_start.copy (); 85 quadratic_segment_stop = segment_stop.copy (); 86 87 PenTool.convert_point_segment_type (quadratic_segment_start, quadratic_segment_stop, PointType.DOUBLE_CURVE); 88 89 distance = 0; 90 e = new EditPoint (); 91 if (segment_start.get_right_handle ().is_line () 92 && segment_stop.get_left_handle ().is_line ()) { 93 // skipping line 94 } else if (points_in_segment >= 10) { 95 warning ("Too many points."); 96 } else { 97 find_largest_distance (segment_start, segment_stop, 98 quadratic_segment_start, quadratic_segment_stop, 99 out distance, out e, out step); 100 } 101 102 if (distance > 0.2) { // range 0.1 - 0.4, 103 quadratic_path.insert_new_point_on_path (e); 104 points_in_segment++; 105 size += 2; // the new point + segment start 106 } else { 107 points_in_segment = 0; 108 segment_start = segment_stop; 109 } 110 } 111 } 112 113 // TODO: Optimize 114 public static void find_largest_distance (EditPoint a0, EditPoint a1, EditPoint b0, EditPoint b1, 115 out double distance, out EditPoint new_point, out double step) { 116 double max_d; 117 double min_d; 118 int steps = (int) (1.6 * Path.get_length_from (a0, a1)); 119 double x_out, y_out; 120 double step_out; 121 122 x_out = 0; 123 y_out = 0; 124 step_out = 0; 125 step = 0; 126 distance = 0; 127 128 new_point = new EditPoint (); 129 new_point.prev = a0; 130 new_point.next = a1; 131 new_point.get_right_handle ().type = PointType.CUBIC; 132 new_point.get_left_handle ().type = PointType.CUBIC; 133 134 steps = 20; // FIXME: adjust to length 135 136 if (a0.get_right_handle ().type == PointType.QUADRATIC 137 || a1.get_left_handle ().type == PointType.QUADRATIC 138 || a0.get_right_handle ().type == PointType.LINE_QUADRATIC 139 || a1.get_left_handle ().type == PointType.LINE_QUADRATIC) { 140 return; 141 } 142 143 max_d = Glyph.CANVAS_MIN; 144 min_d = Glyph.CANVAS_MAX; 145 Path.all_of (a0, a1, (xa, ya, ta) => { 146 147 min_d = double.MAX; 148 Path.all_of (b0, b1, (xb, yb, tb) => { 149 double d = Path.distance (xa, xb, ya, yb); 150 151 if (d < min_d) { 152 min_d = d; 153 } 154 155 return true; 156 }, steps); 157 158 if (min_d > max_d) { 159 max_d = min_d; 160 x_out = xa; 161 y_out = ya; 162 step_out = ta; 163 } 164 165 return true; 166 }, steps); 167 168 distance = max_d; 169 new_point.x = x_out; 170 new_point.y = y_out; 171 step = step_out; 172 } 173 } 174 175 } 176