The Birdfont Source Code


All Repositories / birdfont.git / blob – RSS feed

SvgArc.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/SvgArc.vala.
Tip for deleting points
1 /* 2 * BirdFont code from SVG Salamander 3 * 4 * Copyright (c) 2004, Mark McKay 5 * Copyright (c) 2014, Johan Mattsson 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or 9 * without modification, are permitted provided that the following 10 * conditions are met: 11 * 12 * - Redistributions of source code must retain the above 13 * copyright notice, this list of conditions and the following 14 * disclaimer. 15 * - Redistributions in binary form must reproduce the above 16 * copyright notice, this list of conditions and the following 17 * disclaimer in the documentation and/or other materials 18 * provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 * OF THE POSSIBILITY OF SUCH DAMAGE. 32 * 33 * Mark McKay can be contacted at mark@kitfox.com. Salamander and other 34 * projects can be found at http://www.kitfox.com 35 * 36 * Created on January 26, 2004, 8:40 PM 37 * Adapded to BirdFont on Juli 2, 2014, 5:01 PM 38 */ 39 40 using Math; 41 42 namespace BirdFont { 43 44 /** Convert an SVG arc instruction to a Beziér path. */ 45 static void add_arc_points (BezierPoints[] bezier_points, ref int bi, double x0, double y0, double rx, double ry, double angle, bool largeArcFlag, bool sweepFlag, double x, double y) { 46 47 // 48 // Elliptical arc implementation based on the SVG specification notes 49 // 50 51 double dx2, dy2, cosAngle, sinAngle; 52 double x1, y1, Prx, Pry, Px1, Py1, radiiCheck; 53 double sign, sq, coef, cx1, cy1; 54 double sx2, sy2, cx, cy; 55 double ux, uy, vx, vy, p, n; 56 double angleStart, angleExtent; 57 double s, step, theta; 58 59 // Compute the half distance between the current and the final point 60 dx2 = (x0 - x) / 2.0; 61 dy2 = (y0 - y) / 2.0; 62 63 // Convert angle from degrees to radians 64 angle = 2 * PI * ((angle % 360.0) / 360.0); 65 66 cosAngle = cos (angle); 67 sinAngle = sin (angle); 68 69 // 70 // Step 1 : Compute (x1, y1) 71 // 72 x1 = cosAngle * dx2 + sinAngle * dy2; 73 y1 = -sinAngle * dx2 + cosAngle * dy2; 74 75 // Ensure radii are large enough 76 rx = fabs(rx); 77 ry = fabs(ry); 78 Prx = rx * rx; 79 Pry = ry * ry; 80 Px1 = x1 * x1; 81 Py1 = y1 * y1; 82 83 84 // Check that radii are large enough 85 radiiCheck = Px1 / Prx + Py1 / Pry; 86 87 if (radiiCheck > 1) { 88 rx = sqrt (radiiCheck) * rx; 89 ry = sqrt (radiiCheck) * ry; 90 Prx = rx * rx; 91 Pry = ry * ry; 92 } 93 94 // 95 // Step 2 : Compute (cx1, cy1) 96 // 97 sign = (largeArcFlag == sweepFlag) ? -1 : 1; 98 sq = ((Prx * Pry) - (Prx * Py1) - (Pry * Px1)) / ((Prx * Py1) + (Pry * Px1)); 99 sq = (sq < 0) ? 0 : sq; 100 coef = (sign * Math.sqrt(sq)); 101 cx1 = coef * ((rx * y1) / ry); 102 cy1 = coef * -((ry * x1) / rx); 103 104 // 105 // Step 3 : Compute (cx, cy) from (cx1, cy1) 106 // 107 108 sx2 = (x0 + x) / 2.0; 109 sy2 = (y0 + y) / 2.0; 110 cx = sx2 - (cosAngle * cx1 - sinAngle * cy1); 111 cy = sy2 - (sinAngle * cx1 + cosAngle * cy1); 112 113 // 114 // Step 4 : Compute the angleStart (angle1) and the angleExtent (dangle) 115 // 116 117 ux = (x1 - cx1) / rx; 118 uy = (y1 - cy1) / ry; 119 vx = (-x1 - cx1) / rx; 120 vy = (-y1 - cy1) / ry; 121 122 // Compute the angle start 123 n = sqrt((ux * ux) + (uy * uy)); 124 p = ux; // (1 * ux) + (0 * uy) 125 sign = (uy < 0) ? -1d : 1d; 126 angleStart = sign * acos(p / n); 127 128 // Compute the angle extent 129 n = Math.sqrt((ux * ux + uy * uy) * (vx * vx + vy * vy)); 130 p = ux * vx + uy * vy; 131 sign = (ux * vy - uy * vx < 0) ? -1d : 1d; 132 angleExtent = sign * Math.acos(p / n); 133 134 if(!sweepFlag && angleExtent > 0) { 135 angleExtent -= 2 *PI; 136 } else if (sweepFlag && angleExtent < 0) { 137 angleExtent += 2 *PI; 138 } 139 angleExtent %= 2 * PI; 140 angleStart %= 2 * PI; 141 142 angleExtent *= -1; 143 angleStart *= -1; 144 145 // Approximate the path with Beziér points 146 s = (angleExtent > 0) ? 1 : -1; 147 step = fabs (angleExtent) / (2 * fabs (angleExtent)); 148 149 theta = PI - angleStart - angleExtent; 150 151 bezier_points[bi].type = 'L'; 152 bezier_points[bi].svg_type = 'a'; 153 154 bezier_points[bi].x0 = cx + rx * cos (theta); 155 bezier_points[bi].y0 = cy + ry * sin (theta); 156 157 bi++; 158 159 for (double a = 0; a < fabs (angleExtent); a += step) { 160 theta = PI - angleStart - angleExtent + s * a; 161 162 return_if_fail (0 <= bi < bezier_points.length); 163 164 bezier_points[bi].type = 'S'; 165 bezier_points[bi].svg_type = 'a'; 166 167 bezier_points[bi].x0 = cx + rx * cos (theta); 168 bezier_points[bi].y0 = cy + ry * sin (theta); 169 170 bezier_points[bi].x1 = cx + rx * cos (theta + 1 * step / 4); 171 bezier_points[bi].y1 = cy + ry * sin (theta + 1 * step / 4); 172 173 bezier_points[bi].x2 = cx + rx * cos (theta + 2 * step / 4); 174 bezier_points[bi].y2 = cy + ry * sin (theta + 2 * step / 4); 175 176 bi++; 177 } 178 } 179 180 } 181 182