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.
Remove debug info
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 parent.process_symmetrical_handles (); 52 } 53 } 54 } 55 56 public double y { 57 get { 58 double r = py (); 59 60 if (unlikely (r <= -100000)) { 61 print_position (); 62 move_to (0, 0); 63 } 64 65 return r; 66 } 67 68 set { 69 move_to_coordinate_internal (px (), value); 70 71 if (parent.tie_handles) { 72 parent.process_tied_handle (); 73 } 74 75 if (parent.reflective_point) { 76 parent.process_symmetrical_handles (); 77 } 78 } 79 } 80 81 static int n_handles = 0; 82 83 public EditPointHandle.empty() { 84 this.parent = none; 85 this.angle = 0; 86 this.length = 10; 87 this.type = PointType.NONE; 88 this.active = false; 89 this.selected = false; 90 91 n_handles++; 92 } 93 94 public EditPointHandle (EditPoint parent, double angle, double length) { 95 this.parent = parent; 96 this.angle = angle; 97 this.length = length; 98 this.type = PointType.LINE_CUBIC; 99 this.active = false; 100 this.selected = false; 101 102 n_handles++; 103 104 print (@"EditPointHandle $(n_handles)\n"); 105 } 106 107 ~EditPointHandle () { 108 n_handles--; 109 } 110 111 public EditPointHandle copy () { 112 EditPointHandle n = new EditPointHandle.empty (); 113 n.angle = angle; 114 n.length = length; 115 n.parent = parent; 116 n.type = type; 117 n.active = active; 118 n.selected = selected; 119 return n; 120 } 121 122 public EditPoint get_parent () { 123 return parent; 124 } 125 126 public void convert_to_line () { 127 switch (type) { 128 case PointType.QUADRATIC: 129 type = PointType.LINE_QUADRATIC; 130 break; 131 case PointType.DOUBLE_CURVE: 132 type = PointType.LINE_DOUBLE_CURVE; 133 break; 134 case PointType.CUBIC: 135 type = PointType.LINE_CUBIC; 136 break; 137 default: 138 break; 139 } 140 } 141 142 public bool is_curve () { 143 switch (type) { 144 case PointType.LINE_QUADRATIC: 145 return false; 146 case PointType.LINE_DOUBLE_CURVE: 147 return false; 148 case PointType.LINE_CUBIC: 149 return false; 150 } 151 152 return true; 153 } 154 155 public void convert_to_curve () { 156 switch (type) { 157 case PointType.LINE_QUADRATIC: 158 type = PointType.QUADRATIC; 159 break; 160 case PointType.LINE_DOUBLE_CURVE: 161 type = PointType.DOUBLE_CURVE; 162 break; 163 case PointType.LINE_CUBIC: 164 type = PointType.CUBIC; 165 break; 166 case PointType.QUADRATIC: 167 break; 168 case PointType.DOUBLE_CURVE: 169 break; 170 case PointType.CUBIC: 171 break; 172 default: 173 warning (@"Type $type"); 174 break; 175 } 176 } 177 178 public void set_point_type (PointType point_type) { 179 type = point_type; 180 } 181 182 double px () { 183 assert ((EditPoint?) parent != null); 184 return cos (angle) * length + parent.x; 185 } 186 187 double py () { 188 assert ((EditPoint?) parent != null); 189 return sin (angle) * length + parent.y; 190 } 191 192 internal void print_position () { 193 warning (@"\nEdit point handle at position $(px ()),$(py ()) is not valid.\n" 194 + @"Type: $(parent.type), " 195 + @"Angle: $angle, Length: $length."); 196 } 197 198 public EditPoint get_point () { 199 EditPoint p; 200 201 if (visual_handle == null) { 202 visual_handle = new EditPoint (0, 0); 203 } 204 205 p = (!) visual_handle; 206 p.x = x; 207 p.y = y; 208 209 return p; 210 } 211 212 public bool is_left_handle () { 213 return parent.get_left_handle () == this; 214 } 215 216 public void move_to_coordinate_delta (double dx, double dy) { 217 move_to_coordinate_internal (px () + dx, py () + dy); 218 } 219 220 public void move_to_coordinate (double x, double y) { 221 move_to_coordinate_internal (x, y); 222 223 if (parent.tie_handles) { 224 tie_handle (); 225 } 226 227 if (parent.reflective_point) { 228 tie_handle (); 229 process_symmetrical_handle (); 230 } 231 232 process_connected_handle (); 233 } 234 235 public void move_to_coordinate_internal (double x, double y) { 236 double a, b, c; 237 238 a = parent.x - x; 239 b = parent.y - y; 240 c = a * a + b * b; 241 242 if (unlikely(c == 0)) { 243 angle = 0; // FIXME: this should be a different point type without line handles 244 length = 0; 245 return; 246 } 247 248 length = sqrt (fabs (c)); 249 250 if (c < 0) length = -length; 251 252 if (y < parent.y) { 253 angle = acos (a / length) + PI; 254 } else { 255 angle = -acos (a / length) + PI; 256 } 257 } 258 259 public void process_connected_handle () { 260 EditPointHandle h; 261 262 if (unlikely (type == PointType.NONE)) { 263 warning ("Invalid type."); 264 } 265 266 if (type == PointType.QUADRATIC) { 267 if (!is_left_handle ()) { 268 if (parent.next != null) { 269 h = parent.get_next ().get_left_handle (); 270 h.parent.set_tie_handle (false); 271 h.type = PointType.QUADRATIC; 272 h.move_to_coordinate_internal (px (), py ()); 273 } 274 } else { 275 if (parent.prev != null) { 276 h = parent.get_prev ().get_right_handle (); 277 h.parent.set_tie_handle (false); 278 h.type = PointType.QUADRATIC; 279 h.move_to_coordinate_internal (px (), py ()); 280 } 281 } 282 } 283 } 284 285 public void process_symmetrical_handle () { 286 if (is_left_handle ()) { 287 parent.get_right_handle ().length = length; 288 parent.get_right_handle ().process_connected_handle (); 289 } else { 290 parent.get_left_handle ().length = length; 291 parent.get_left_handle ().process_connected_handle (); 292 } 293 294 process_connected_handle (); 295 } 296 297 public void tie_handle () { 298 if (is_left_handle ()) { 299 parent.get_right_handle ().angle = angle - PI; 300 parent.get_right_handle ().process_connected_handle (); 301 } else { 302 parent.get_left_handle ().angle = angle - PI; 303 parent.get_left_handle ().process_connected_handle (); 304 } 305 306 process_connected_handle (); 307 } 308 309 public void move_delta_coordinate (double dx, double dy) { 310 double px = px () + dx; 311 double py = py () + dy; 312 move_to_coordinate (px, py); 313 } 314 315 public void move_to (double x, double y) { 316 EditPoint.to_coordinate (ref x, ref y); 317 move_to_coordinate (x, y); 318 } 319 320 public bool is_line () { 321 return PenTool.is_line (type); 322 } 323 } 324 325 } 326