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

Revisions

View the latest version of libsvgbird/Points.vala.
Insert points in SVG paths
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, uchar 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, uchar 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 (uchar 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 int index; 60 61 if (size == 0) { 62 index = 0; 63 insert_type (index, POINT_LINE); 64 insert (index + 1, x); 65 insert (index + 2, y); 66 insert (index + 3, 0); 67 insert (index + 4, 0); 68 insert (index + 5, 0); 69 insert (index + 6, 0); 70 insert (index + 7, 0); 71 } 72 73 index = size; 74 insert_type (index, POINT_CUBIC); 75 insert (index + 1, handle_x); 76 insert (index + 2, handle_y); 77 insert (index + 3, next_handle_x); 78 insert (index + 4, next_handle_y); 79 insert (index + 5, x); 80 insert (index + 6, y); 81 insert (index + 7, 0); 82 83 return index; 84 } 85 86 public Points copy () { 87 Points p = new Points (); 88 p.point_data = point_data.copy (); 89 p.closed = closed; 90 return p; 91 } 92 93 public double get_double (int index) { 94 return point_data.get_double (index); 95 } 96 97 public uchar get_point_type (int index) { 98 return point_data.get_point_type (index); 99 } 100 101 public void all (LineIterator iter) { 102 double previous_x; 103 double previous_y; 104 105 PointValue* points = point_data.data; 106 int size = point_data.size; 107 108 return_if_fail (size % 8 == 0); 109 110 SvgPath.get_start (this, out previous_x, out previous_y); 111 112 for (int i = 8; i < size; i += 8) { 113 switch (points[i].type) { 114 case POINT_ARC: 115 double rx = points[i + 1].value; 116 double ry = points[i + 2].value; 117 double rotation = points[i + 3].value; 118 double large_arc = points[i + 4].value; 119 double sweep = points[i + 5].value; 120 double dest_x = points[i + 6].value; 121 double dest_y = points[i + 7].value; 122 123 double angle_start, angle_extent, cx, cy; 124 125 get_arc_arguments (previous_x, previous_y, rx, ry, 126 rotation, large_arc > 0, sweep > 0, dest_x, dest_y, 127 out angle_start, out angle_extent, 128 out cx, out cy); 129 130 const int steps = 50; 131 for (int step = 0; step < steps; step++) { 132 double angle = angle_start + step * (angle_extent / steps); 133 double next_x = cx + cos (angle); 134 double next_y = cy + sin (angle); 135 136 iter (previous_x, previous_y, next_x, next_y, step / steps, i); 137 138 previous_x = next_x; 139 previous_y = next_y; 140 } 141 break; 142 case POINT_CUBIC: 143 all_lines (previous_x, previous_y, 144 points[i + 1].value, points[i + 2].value, 145 points[i + 3].value, points[i + 4].value, 146 points[i + 5].value, points[i + 6].value, 147 iter, 148 i); 149 150 previous_x = points[i + 5].value; 151 previous_y = points[i + 6].value; 152 break; 153 case POINT_LINE: 154 double x = points[i + 1].value; 155 double y = points[i + 2].value; 156 157 iter (previous_x, previous_y, x, y, 1, i); 158 159 previous_x = x; 160 previous_y = y; 161 break; 162 } 163 } 164 } 165 166 private static bool all_lines (double x0, double y0, double x1, double y1, double x2, double y2, double x3, double y3, 167 LineIterator iter, int index = 0, double steps = 400) { 168 double px = x1; 169 double py = y1; 170 171 double t; 172 173 double previous_x = px; 174 double previous_y = py; 175 176 for (int i = 0; i < steps; i++) { 177 t = i / steps; 178 179 px = bezier_path (t, x0, x1, x2, x3); 180 py = bezier_path (t, y0, y1, y2, y3); 181 182 if (!iter (previous_x, previous_y, px, py, t, index)) { 183 return false; 184 } 185 186 previous_x = px; 187 previous_y = py; 188 } 189 190 return true; 191 } 192 193 public static double bezier_path (double step, double p0, double p1, double p2, double p3) { 194 double q0, q1, q2; 195 double r0, r1; 196 197 q0 = step * (p1 - p0) + p0; 198 q1 = step * (p2 - p1) + p1; 199 q2 = step * (p3 - p2) + p2; 200 201 r0 = step * (q1 - q0) + q0; 202 r1 = step * (q2 - q1) + q1; 203 204 return step * (r1 - r0) + r0; 205 } 206 207 public static void bezier_vector (double step, double p0, double p1, double p2, double p3, out double a0, out double a1) { 208 double q0, q1, q2; 209 210 q0 = step * (p1 - p0) + p0; 211 q1 = step * (p2 - p1) + p1; 212 q2 = step * (p3 - p2) + p2; 213 214 a0 = step * (q1 - q0) + q0; 215 a1 = step * (q2 - q1) + q1; 216 } 217 } 218 219 } 220 221