Skip to content

Instantly share code, notes, and snippets.

@devongovett
Created June 4, 2010 02:28
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save devongovett/424839 to your computer and use it in GitHub Desktop.
Save devongovett/424839 to your computer and use it in GitHub Desktop.
/*
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