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