The Birdfont Source Code


All Repositories / birdfont.git / blob – RSS feed

EditPointHandle.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/EditPointHandle.vala.
Fix translation
1 /* 2 Copyright (C) 2012 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 Math; 16 17 namespace BirdFont { 18 19 public class EditPointHandle : GLib.Object { 20 21 public double length; 22 public unowned EditPoint parent; 23 public PointType type; 24 EditPoint? visual_handle = null; 25 static EditPoint none = new EditPoint (); 26 public bool active; 27 public bool selected; 28 29 public double angle; 30 31 public double x { 32 get { 33 double r = px (); 34 35 if (unlikely (r <= -100000)) { 36 print_position (); 37 move_to (0, 0); 38 } 39 40 return r; 41 } 42 43 set { 44 move_to_coordinate_internal (value, py ()); 45 46 if (parent.tie_handles) { 47 parent.process_tied_handle (); 48 } 49 50 if (parent.reflective_point) { 51 process_symmetrical_handle (); 52 } 53 54 process_connected_handle (); 55 } 56 } 57 58 public double y { 59 get { 60 double r = py (); 61 62 if (unlikely (r <= -100000)) { 63 print_position (); 64 move_to (0, 0); 65 } 66 67 return r; 68 } 69 70 set { 71 move_to_coordinate_internal (px (), value); 72 73 if (parent.tie_handles) { 74 parent.process_tied_handle (); 75 } 76 77 if (parent.reflective_point) { 78 process_symmetrical_handle (); 79 } 80 81 process_connected_handle (); 82 } 83 } 84 85 public double independent_x { 86 get { 87 double r = px (); 88 89 if (unlikely (r <= -100000)) { 90 print_position (); 91 move_to (0, 0); 92 } 93 94 return r; 95 } 96 97 set { 98 move_to_coordinate_internal (value, py ()); 99 } 100 } 101 102 public double independent_y { 103 get { 104 double r = py (); 105 106 if (unlikely (r <= -100000)) { 107 print_position (); 108 move_to (0, 0); 109 } 110 111 return r; 112 } 113 114 set { 115 move_to_coordinate_internal (px (), value); 116 } 117 } 118 119 public EditPointHandle.empty() { 120 this.parent = none; 121 this.angle = 0; 122 this.length = 10; 123 this.type = PointType.NONE; 124 this.active = false; 125 this.selected = false; 126 } 127 128 public EditPointHandle (EditPoint parent, double angle, double length) { 129 this.parent = parent; 130 this.angle = angle; 131 this.length = length; 132 this.type = PointType.LINE_CUBIC; 133 this.active = false; 134 this.selected = false; 135 } 136 137 public EditPointHandle copy () { 138 EditPointHandle n = new EditPointHandle.empty (); 139 n.angle = angle; 140 n.length = length; 141 n.parent = parent; 142 n.type = type; 143 n.active = active; 144 n.selected = selected; 145 return n; 146 } 147 148 public EditPoint get_parent () { 149 return parent; 150 } 151 152 public void convert_to_line () { 153 parent.tie_handles = false; 154 parent.reflective_point = false; 155 156 switch (type) { 157 case PointType.QUADRATIC: 158 type = PointType.LINE_QUADRATIC; 159 break; 160 case PointType.DOUBLE_CURVE: 161 type = PointType.LINE_DOUBLE_CURVE; 162 break; 163 case PointType.CUBIC: 164 type = PointType.LINE_CUBIC; 165 break; 166 default: 167 break; 168 } 169 } 170 171 public bool is_curve () { 172 switch (type) { 173 case PointType.LINE_QUADRATIC: 174 return false; 175 case PointType.LINE_DOUBLE_CURVE: 176 return false; 177 case PointType.LINE_CUBIC: 178 return false; 179 } 180 181 return true; 182 } 183 184 public void convert_to_curve () { 185 switch (type) { 186 case PointType.LINE_QUADRATIC: 187 type = PointType.QUADRATIC; 188 break; 189 case PointType.LINE_DOUBLE_CURVE: 190 type = PointType.DOUBLE_CURVE; 191 break; 192 case PointType.LINE_CUBIC: 193 type = PointType.CUBIC; 194 break; 195 case PointType.QUADRATIC: 196 break; 197 case PointType.DOUBLE_CURVE: 198 break; 199 case PointType.CUBIC: 200 break; 201 default: 202 warning (@"Type $type"); 203 break; 204 } 205 } 206 207 public void set_point_type (PointType point_type) { 208 type = point_type; 209 } 210 211 double px () { 212 assert ((EditPoint?) parent != null); 213 return cos (angle) * length + parent.x; 214 } 215 216 double py () { 217 assert ((EditPoint?) parent != null); 218 return sin (angle) * length + parent.y; 219 } 220 221 internal void print_position () { 222 warning (@"\nEdit point handle at position $(px ()),$(py ()) is not valid.\n" 223 + @"Type: $(parent.type), " 224 + @"Angle: $angle, Length: $length."); 225 } 226 227 public EditPoint get_point () { 228 EditPoint p; 229 230 if (visual_handle == null) { 231 visual_handle = new EditPoint (0, 0); 232 } 233 234 p = (!) visual_handle; 235 p.x = x; 236 p.y = y; 237 238 return p; 239 } 240 241 public bool is_left_handle () { 242 return parent.get_left_handle () == this; 243 } 244 245 public void move_to_coordinate_delta (double dx, double dy) { 246 move_to_coordinate_internal (px () + dx, py () + dy); 247 } 248 249 public void move_to_coordinate (double x, double y) { 250 move_to_coordinate_internal (x, y); 251 252 if (parent.tie_handles) { 253 tie_handle (); 254 } 255 256 if (parent.reflective_point) { 257 tie_handle (); 258 process_symmetrical_handle (); 259 } 260 261 process_connected_handle (); 262 } 263 264 public void move_to_coordinate_internal (double x, double y) { 265 double a, b, c; 266 267 a = parent.x - x; 268 b = parent.y - y; 269 c = a * a + b * b; 270 271 if (unlikely(c == 0)) { 272 angle = 0; // FIXME: this should be a different point type without line handles 273 length = 0; 274 return; 275 } 276 277 length = sqrt (fabs (c)); 278 279 if (c < 0) length = -length; 280 281 if (y < parent.y) { 282 angle = acos (a / length) + PI; 283 } else { 284 angle = -acos (a / length) + PI; 285 } 286 } 287 288 public void process_connected_handle () { 289 EditPointHandle h; 290 291 if (unlikely (type == PointType.NONE)) { 292 warning ("Invalid type."); 293 } 294 295 if (type == PointType.QUADRATIC) { 296 if (!is_left_handle ()) { 297 if (parent.next != null) { 298 h = parent.get_next ().get_left_handle (); 299 h.parent.set_reflective_handles (false); 300 h.parent.set_tie_handle (false); 301 h.type = PointType.QUADRATIC; 302 h.move_to_coordinate_internal (x, y); 303 } 304 } else { 305 if (parent.prev != null) { 306 h = parent.get_prev ().get_right_handle (); 307 h.parent.set_reflective_handles (false); 308 h.parent.set_tie_handle (false); 309 h.type = PointType.QUADRATIC; 310 h.move_to_coordinate_internal (x, y); 311 } 312 } 313 } 314 } 315 316 public void process_symmetrical_handle () { 317 if (is_left_handle ()) { 318 parent.get_right_handle ().length = length; 319 parent.get_right_handle ().process_connected_handle (); 320 } else { 321 parent.get_left_handle ().length = length; 322 parent.get_left_handle ().process_connected_handle (); 323 } 324 325 process_connected_handle (); 326 } 327 328 public void tie_handle () { 329 if (is_left_handle ()) { 330 parent.get_right_handle ().angle = angle - PI; 331 parent.get_right_handle ().process_connected_handle (); 332 } else { 333 parent.get_left_handle ().angle = angle - PI; 334 parent.get_left_handle ().process_connected_handle (); 335 } 336 337 process_connected_handle (); 338 } 339 340 public void move_delta_coordinate (double dx, double dy) { 341 double px = px () + dx; 342 double py = py () + dy; 343 move_to_coordinate (px, py); 344 } 345 346 public void move_to (double x, double y) { 347 EditPoint.to_coordinate (ref x, ref y); 348 move_to_coordinate (x, y); 349 } 350 351 public bool is_line () { 352 return PenTool.is_line (type); 353 } 354 355 public static double average_angle (double angle1, double angle2) { 356 EditPointHandle handle = new EditPointHandle (new EditPoint (0, 0, PointType.CUBIC), 0, 1); 357 double x = (cos (angle1) + cos (angle2)) / 2; 358 double y = (sin (angle1) + sin (angle2)) / 2; 359 handle.move_to_coordinate (x, y); 360 361 if (fabs (x) < 0.001 && fabs (y) < 0.001) { 362 return (angle1 + PI / 2) % (2 * PI); 363 } 364 365 return handle.angle; 366 } 367 368 } 369 370 } 371