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.
Cache overview items
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 (!original_path.is_open ()) { 52 if (quadratic_path.get_last_point ().get_right_handle ().type == PointType.CUBIC) { 53 PenTool.convert_point_segment_type (quadratic_path.get_last_point (), 54 quadratic_path.get_first_point (), 55 PointType.DOUBLE_CURVE); 56 } 57 } 58 59 quadratic_path.add_hidden_double_points (); 60 61 return quadratic_path; 62 } 63 64 public void estimated_cubic_path () { 65 EditPoint segment_start; 66 EditPoint segment_stop; 67 EditPoint quadratic_segment_start; 68 EditPoint quadratic_segment_stop; 69 EditPoint e; 70 double distance, step; 71 int points_in_segment = 0; 72 int size; 73 74 foreach (EditPoint ep in quadratic_path.points) { 75 ep.set_tie_handle (false); 76 ep.set_reflective_handles (false); 77 } 78 79 size = quadratic_path.points.size; 80 segment_start = quadratic_path.get_first_point (); 81 82 if (original_path.is_open ()) { 83 size--; 84 } 85 86 for (int i = 0; i < size; i++) { 87 segment_stop = (i == size -1) 88 ? quadratic_path.get_first_point () 89 : segment_start.get_next (); 90 91 quadratic_segment_start = segment_start.copy (); 92 quadratic_segment_stop = segment_stop.copy (); 93 94 PenTool.convert_point_segment_type (quadratic_segment_start, quadratic_segment_stop, PointType.DOUBLE_CURVE); 95 96 distance = 0; 97 e = new EditPoint (); 98 if (segment_start.get_right_handle ().is_line () 99 && segment_stop.get_left_handle ().is_line ()) { 100 // skipping line 101 } else if (points_in_segment >= 10) { 102 warning ("Too many points."); 103 } else { 104 find_largest_distance (segment_start, segment_stop, 105 quadratic_segment_start, quadratic_segment_stop, 106 out distance, out e, out step); 107 } 108 109 if (distance > 0.2) { // range 0.1 - 0.4, 110 quadratic_path.insert_new_point_on_path (e); 111 points_in_segment++; 112 size += 2; // the new point + segment start 113 } else { 114 points_in_segment = 0; 115 segment_start = segment_stop; 116 } 117 } 118 } 119 120 // TODO: Optimize 121 public static void find_largest_distance (EditPoint a0, EditPoint a1, EditPoint b0, EditPoint b1, 122 out double distance, out EditPoint new_point, out double step) { 123 double max_d; 124 double min_d; 125 int steps = (int) (1.6 * Path.get_length_from (a0, a1)); 126 double x_out, y_out; 127 double step_out; 128 129 x_out = 0; 130 y_out = 0; 131 step_out = 0; 132 step = 0; 133 distance = 0; 134 135 new_point = new EditPoint (); 136 new_point.prev = a0; 137 new_point.next = a1; 138 new_point.get_right_handle ().type = PointType.CUBIC; 139 new_point.get_left_handle ().type = PointType.CUBIC; 140 141 steps = 20; // FIXME: adjust to length 142 143 if (a0.get_right_handle ().type == PointType.QUADRATIC 144 || a1.get_left_handle ().type == PointType.QUADRATIC 145 || a0.get_right_handle ().type == PointType.LINE_QUADRATIC 146 || a1.get_left_handle ().type == PointType.LINE_QUADRATIC) { 147 return; 148 } 149 150 max_d = Glyph.CANVAS_MIN; 151 min_d = Glyph.CANVAS_MAX; 152 Path.all_of (a0, a1, (xa, ya, ta) => { 153 154 min_d = double.MAX; 155 Path.all_of (b0, b1, (xb, yb, tb) => { 156 double d = Path.distance (xa, xb, ya, yb); 157 158 if (d < min_d) { 159 min_d = d; 160 } 161 162 return true; 163 }, steps); 164 165 if (min_d > max_d) { 166 max_d = min_d; 167 x_out = xa; 168 y_out = ya; 169 step_out = ta; 170 } 171 172 return true; 173 }, steps); 174 175 distance = max_d; 176 new_point.x = x_out; 177 new_point.y = y_out; 178 step = step_out; 179 } 180 } 181 182 } 183