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