The Birdfont Source Code


All Repositories / birdfont.git / blob – RSS feed

Points.vala in /libsvgbird

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
Circle boundaries heads/master
1 /* 2 Copyright (C) 2016 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 SvgBird { 19 20 public class Points : GLib.Object { 21 public Doubles point_data = new Doubles.for_capacity (100); 22 public bool closed; 23 public delegate bool LineIterator (double start_x, double start_y, double end_x, double end_y, double step, int point_index); 24 25 public int size { 26 get { 27 return point_data.size; 28 } 29 } 30 31 public void set_type (int index, uint32 p) { 32 point_data.set_type (index, p); 33 } 34 35 public void set_double (int index, double p) { 36 point_data.set_double (index, p); 37 } 38 39 public void insert_type (int index, uint32 t) { 40 point_data.insert_type (index, t); 41 } 42 43 public void insert (int index, double p) { 44 point_data.insert (index, p); 45 } 46 47 public void add (double p) { 48 point_data.add (p); 49 } 50 51 public void add_type (uint32 type) { 52 point_data.add_type (type); 53 } 54 55 public int add_cubic (double handle_x, double handle_y, 56 double next_handle_x, double next_handle_y, 57 double x, double y) { 58 59 return insert_cubic (size, handle_x, handle_y, 60 next_handle_x, next_handle_y, x, y); 61 } 62 63 public int add_line (double x, double y) { 64 return insert_line (size, x, y); 65 } 66 67 public int insert_cubic (int position, double handle_x, double handle_y, 68 double next_handle_x, double next_handle_y, 69 double x, double y) { 70 71 int index; 72 73 if (size == 0) { 74 insert_line (0, x, y); 75 } 76 77 index = position; 78 insert_type (index, POINT_CUBIC); 79 insert (index + 1, handle_x); 80 insert (index + 2, handle_y); 81 insert (index + 3, next_handle_x); 82 insert (index + 4, next_handle_y); 83 insert (index + 5, x); 84 insert (index + 6, y); 85 insert (index + 7, 0); 86 87 return index; 88 } 89 90 public int insert_line (int position, double x, double y) { 91 int index = position; 92 93 insert_type (index, POINT_LINE); 94 insert (index + 1, x); 95 insert (index + 2, y); 96 insert (index + 3, 0); 97 insert (index + 4, 0); 98 insert (index + 5, 0); 99 insert (index + 6, 0); 100 insert (index + 7, 0); 101 102 return index; 103 } 104 105 public Points copy () { 106 Points p = new Points (); 107 p.point_data = point_data.copy (); 108 p.closed = closed; 109 return p; 110 } 111 112 public double get_double (int index) { 113 return point_data.get_double (index); 114 } 115 116 public uint32 get_point_type (int index) { 117 return point_data.get_point_type (index); 118 } 119 120 public void set_point_type (int index, uint32 type) { 121 point_data.set_point_type (index, type); 122 } 123 124 public void all (LineIterator iter) { 125 double previous_x; 126 double previous_y; 127 128 PointValue* points = point_data.data; 129 int size = point_data.size; 130 131 return_if_fail (size % 8 == 0); 132 133 SvgPath.get_start (this, out previous_x, out previous_y); 134 135 for (int i = 8; i < size; i += 8) { 136 switch (points[i].type) { 137 case POINT_ARC: 138 double rx = points[i + 1].value; 139 double ry = points[i + 2].value; 140 double rotation = points[i + 3].value; 141 double large_arc = points[i + 4].value; 142 double sweep = points[i + 5].value; 143 double dest_x = points[i + 6].value; 144 double dest_y = points[i + 7].value; 145 146 double angle_start, angle_extent, cx, cy; 147 148 get_arc_arguments (previous_x, previous_y, rx, ry, 149 rotation, large_arc > 0, sweep > 0, dest_x, dest_y, 150 out angle_start, out angle_extent, 151 out cx, out cy); 152 153 const int steps = 50; 154 for (int step = 0; step < steps; step++) { 155 double angle = angle_start + step * (angle_extent / steps); 156 double next_x = cx + cos (angle); 157 double next_y = cy + sin (angle); 158 159 iter (previous_x, previous_y, next_x, next_y, step / steps, i); 160 161 previous_x = next_x; 162 previous_y = next_y; 163 } 164 break; 165 case POINT_CUBIC: 166 all_lines (previous_x, previous_y, 167 points[i + 1].value, points[i + 2].value, 168 points[i + 3].value, points[i + 4].value, 169 points[i + 5].value, points[i + 6].value, 170 iter, 171 i); 172 173 previous_x = points[i + 5].value; 174 previous_y = points[i + 6].value; 175 break; 176 case POINT_LINE: 177 double x = points[i + 1].value; 178 double y = points[i + 2].value; 179 180 iter (previous_x, previous_y, x, y, 1, i); 181 182 previous_x = x; 183 previous_y = y; 184 break; 185 } 186 } 187 } 188 189 private static bool all_lines (double x0, double y0, double x1, double y1, double x2, double y2, double x3, double y3, 190 LineIterator iter, int index = 0, double steps = 400) { 191 double px = x1; 192 double py = y1; 193 194 double t; 195 196 double previous_x = px; 197 double previous_y = py; 198 199 for (int i = 0; i < steps; i++) { 200 t = i / steps; 201 202 px = bezier_path (t, x0, x1, x2, x3); 203 py = bezier_path (t, y0, y1, y2, y3); 204 205 if (!iter (previous_x, previous_y, px, py, t, index)) { 206 return false; 207 } 208 209 previous_x = px; 210 previous_y = py; 211 } 212 213 return true; 214 } 215 216 public static double bezier_path (double step, double p0, double p1, double p2, double p3) { 217 double q0, q1, q2; 218 double r0, r1; 219 220 q0 = step * (p1 - p0) + p0; 221 q1 = step * (p2 - p1) + p1; 222 q2 = step * (p3 - p2) + p2; 223 224 r0 = step * (q1 - q0) + q0; 225 r1 = step * (q2 - q1) + q1; 226 227 return step * (r1 - r0) + r0; 228 } 229 230 public static void bezier_vector (double step, double p0, double p1, double p2, double p3, out double a0, out double a1) { 231 double q0, q1, q2; 232 233 q0 = step * (p1 - p0) + p0; 234 q1 = step * (p2 - p1) + p1; 235 q2 = step * (p3 - p2) + p2; 236 237 a0 = step * (q1 - q0) + q0; 238 a1 = step * (q2 - q1) + q1; 239 } 240 } 241 242 } 243 244