Created
June 4, 2010 02:28
-
-
Save devongovett/424839 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Render SVG Arc with canvas commands | |
Usage: solveArc(x, y, coords) | |
*/ | |
function solveArc(x, y, coords) { | |
var rx = coords[0] | |
var ry = coords[1] | |
var rot = coords[2] | |
var large = coords[3] | |
var sweep = coords[4] | |
var ex = coords[5] | |
var ey = coords[6] | |
var segs = arcToSegments(ex, ey, rx, ry, large, sweep, rot, x, y) | |
for (var i=0; i<segs.length; i++) { | |
var bez = segmentToBezier.apply(this, segs[i]) | |
ctx.bezierCurveTo.apply(ctx, bez) | |
} | |
} | |
// Copied from Inkscape svgtopdf, thanks! | |
function arcToSegments(x, y, rx, ry, large, sweep, rotateX, ox, oy) { | |
var th = rotateX * (Math.PI/180) | |
var sin_th = Math.sin(th) | |
var cos_th = Math.cos(th) | |
rx = Math.abs(rx) | |
ry = Math.abs(ry) | |
var px = cos_th * (ox - x) * 0.5 + sin_th * (oy - y) * 0.5 | |
var py = cos_th * (oy - y) * 0.5 - sin_th * (ox - x) * 0.5 | |
var pl = (px*px) / (rx*rx) + (py*py) / (ry*ry) | |
if (pl > 1) { | |
pl = Math.sqrt(pl) | |
rx *= pl | |
ry *= pl | |
} | |
var a00 = cos_th / rx | |
var a01 = sin_th / rx | |
var a10 = (-sin_th) / ry | |
var a11 = (cos_th) / ry | |
var x0 = a00 * ox + a01 * oy | |
var y0 = a10 * ox + a11 * oy | |
var x1 = a00 * x + a01 * y | |
var y1 = a10 * x + a11 * y | |
var d = (x1-x0) * (x1-x0) + (y1-y0) * (y1-y0) | |
var sfactor_sq = 1 / d - 0.25 | |
if (sfactor_sq < 0) sfactor_sq = 0 | |
var sfactor = Math.sqrt(sfactor_sq) | |
if (sweep == large) sfactor = -sfactor | |
var xc = 0.5 * (x0 + x1) - sfactor * (y1-y0) | |
var yc = 0.5 * (y0 + y1) + sfactor * (x1-x0) | |
var th0 = Math.atan2(y0-yc, x0-xc) | |
var th1 = Math.atan2(y1-yc, x1-xc) | |
var th_arc = th1-th0 | |
if (th_arc < 0 && sweep == 1){ | |
th_arc += 2*Math.PI | |
} else if (th_arc > 0 && sweep == 0) { | |
th_arc -= 2 * Math.PI | |
} | |
var segments = Math.ceil(Math.abs(th_arc / (Math.PI * 0.5 + 0.001))) | |
var result = [] | |
for (var i=0; i<segments; i++) { | |
var th2 = th0 + i * th_arc / segments | |
var th3 = th0 + (i+1) * th_arc / segments | |
result[i] = [xc, yc, th2, th3, rx, ry, sin_th, cos_th] | |
} | |
return result | |
} | |
function segmentToBezier(cx, cy, th0, th1, rx, ry, sin_th, cos_th) { | |
var a00 = cos_th * rx | |
var a01 = -sin_th * ry | |
var a10 = sin_th * rx | |
var a11 = cos_th * ry | |
var th_half = 0.5 * (th1 - th0) | |
var t = (8/3) * Math.sin(th_half * 0.5) * Math.sin(th_half * 0.5) / Math.sin(th_half) | |
var x1 = cx + Math.cos(th0) - t * Math.sin(th0) | |
var y1 = cy + Math.sin(th0) + t * Math.cos(th0) | |
var x3 = cx + Math.cos(th1) | |
var y3 = cy + Math.sin(th1) | |
var x2 = x3 + t * Math.sin(th1) | |
var y2 = y3 - t * Math.cos(th1) | |
return [ | |
a00 * x1 + a01 * y1, a10 * x1 + a11 * y1, | |
a00 * x2 + a01 * y2, a10 * x2 + a11 * y2, | |
a00 * x3 + a01 * y3, a10 * x3 + a11 * y3 | |
] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment