You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
typesetting/pitfall/pdfkit/lib/path.js

367 lines
9.6 KiB
JavaScript

// Generated by CoffeeScript 1.12.5
(function() {
var SVGPath;
SVGPath = (function() {
var apply, arcToSegments, cx, cy, parameters, parse, px, py, runners, segmentToBezier, solveArc, sx, sy;
function SVGPath() {}
SVGPath.apply = function(doc, path) {
var commands;
commands = parse(path);
return apply(commands, doc);
};
parameters = {
A: 7,
a: 7,
C: 6,
c: 6,
H: 1,
h: 1,
L: 2,
l: 2,
M: 2,
m: 2,
Q: 4,
q: 4,
S: 4,
s: 4,
T: 2,
t: 2,
V: 1,
v: 1,
Z: 0,
z: 0
};
parse = function(path) {
var args, c, cmd, curArg, foundDecimal, j, len, params, ret;
ret = [];
args = [];
curArg = "";
foundDecimal = false;
params = 0;
for (j = 0, len = path.length; j < len; j++) {
c = path[j];
if (parameters[c] != null) {
params = parameters[c];
if (cmd) {
if (curArg.length > 0) {
args[args.length] = +curArg;
}
ret[ret.length] = {
cmd: cmd,
args: args
};
args = [];
curArg = "";
foundDecimal = false;
}
cmd = c;
} else if ((c === " " || c === ",") || (c === "-" && curArg.length > 0 && curArg[curArg.length - 1] !== 'e') || (c === "." && foundDecimal)) {
if (curArg.length === 0) {
continue;
}
if (args.length === params) {
ret[ret.length] = {
cmd: cmd,
args: args
};
args = [+curArg];
if (cmd === "M") {
cmd = "L";
}
if (cmd === "m") {
cmd = "l";
}
} else {
args[args.length] = +curArg;
}
foundDecimal = c === ".";
curArg = c === '-' || c === '.' ? c : '';
} else {
curArg += c;
if (c === '.') {
foundDecimal = true;
}
}
}
if (curArg.length > 0) {
if (args.length === params) {
ret[ret.length] = {
cmd: cmd,
args: args
};
args = [+curArg];
if (cmd === "M") {
cmd = "L";
}
if (cmd === "m") {
cmd = "l";
}
} else {
args[args.length] = +curArg;
}
}
ret[ret.length] = {
cmd: cmd,
args: args
};
return ret;
};
cx = cy = px = py = sx = sy = 0;
apply = function(commands, doc) {
var c, i, j, len, name;
cx = cy = px = py = sx = sy = 0;
for (i = j = 0, len = commands.length; j < len; i = ++j) {
c = commands[i];
if (typeof runners[name = c.cmd] === "function") {
runners[name](doc, c.args);
}
}
return cx = cy = px = py = 0;
};
runners = {
M: function(doc, a) {
cx = a[0];
cy = a[1];
px = py = null;
sx = cx;
sy = cy;
return doc.moveTo(cx, cy);
},
m: function(doc, a) {
cx += a[0];
cy += a[1];
px = py = null;
sx = cx;
sy = cy;
return doc.moveTo(cx, cy);
},
C: function(doc, a) {
cx = a[4];
cy = a[5];
px = a[2];
py = a[3];
return doc.bezierCurveTo.apply(doc, a);
},
c: function(doc, a) {
doc.bezierCurveTo(a[0] + cx, a[1] + cy, a[2] + cx, a[3] + cy, a[4] + cx, a[5] + cy);
px = cx + a[2];
py = cy + a[3];
cx += a[4];
return cy += a[5];
},
S: function(doc, a) {
if (px === null) {
px = cx;
py = cy;
}
doc.bezierCurveTo(cx - (px - cx), cy - (py - cy), a[0], a[1], a[2], a[3]);
px = a[0];
py = a[1];
cx = a[2];
return cy = a[3];
},
s: function(doc, a) {
if (px === null) {
px = cx;
py = cy;
}
doc.bezierCurveTo(cx - (px - cx), cy - (py - cy), cx + a[0], cy + a[1], cx + a[2], cy + a[3]);
px = cx + a[0];
py = cy + a[1];
cx += a[2];
return cy += a[3];
},
Q: function(doc, a) {
px = a[0];
py = a[1];
cx = a[2];
cy = a[3];
return doc.quadraticCurveTo(a[0], a[1], cx, cy);
},
q: function(doc, a) {
doc.quadraticCurveTo(a[0] + cx, a[1] + cy, a[2] + cx, a[3] + cy);
px = cx + a[0];
py = cy + a[1];
cx += a[2];
return cy += a[3];
},
T: function(doc, a) {
if (px === null) {
px = cx;
py = cy;
} else {
px = cx - (px - cx);
py = cy - (py - cy);
}
doc.quadraticCurveTo(px, py, a[0], a[1]);
px = cx - (px - cx);
py = cy - (py - cy);
cx = a[0];
return cy = a[1];
},
t: function(doc, a) {
if (px === null) {
px = cx;
py = cy;
} else {
px = cx - (px - cx);
py = cy - (py - cy);
}
doc.quadraticCurveTo(px, py, cx + a[0], cy + a[1]);
cx += a[0];
return cy += a[1];
},
A: function(doc, a) {
solveArc(doc, cx, cy, a);
cx = a[5];
return cy = a[6];
},
a: function(doc, a) {
a[5] += cx;
a[6] += cy;
solveArc(doc, cx, cy, a);
cx = a[5];
return cy = a[6];
},
L: function(doc, a) {
cx = a[0];
cy = a[1];
px = py = null;
return doc.lineTo(cx, cy);
},
l: function(doc, a) {
cx += a[0];
cy += a[1];
px = py = null;
return doc.lineTo(cx, cy);
},
H: function(doc, a) {
cx = a[0];
px = py = null;
return doc.lineTo(cx, cy);
},
h: function(doc, a) {
cx += a[0];
px = py = null;
return doc.lineTo(cx, cy);
},
V: function(doc, a) {
cy = a[0];
px = py = null;
return doc.lineTo(cx, cy);
},
v: function(doc, a) {
cy += a[0];
px = py = null;
return doc.lineTo(cx, cy);
},
Z: function(doc) {
doc.closePath();
cx = sx;
return cy = sy;
},
z: function(doc) {
doc.closePath();
cx = sx;
return cy = sy;
}
};
solveArc = function(doc, x, y, coords) {
var bez, ex, ey, j, large, len, results, rot, rx, ry, seg, segs, sweep;
rx = coords[0], ry = coords[1], rot = coords[2], large = coords[3], sweep = coords[4], ex = coords[5], ey = coords[6];
segs = arcToSegments(ex, ey, rx, ry, large, sweep, rot, x, y);
results = [];
for (j = 0, len = segs.length; j < len; j++) {
seg = segs[j];
bez = segmentToBezier.apply(null, seg);
results.push(doc.bezierCurveTo.apply(doc, bez));
}
return results;
};
arcToSegments = function(x, y, rx, ry, large, sweep, rotateX, ox, oy) {
var a00, a01, a10, a11, cos_th, d, i, j, pl, ref, result, segments, sfactor, sfactor_sq, sin_th, th, th0, th1, th2, th3, th_arc, x0, x1, xc, y0, y1, yc;
th = rotateX * (Math.PI / 180);
sin_th = Math.sin(th);
cos_th = Math.cos(th);
rx = Math.abs(rx);
ry = Math.abs(ry);
px = cos_th * (ox - x) * 0.5 + sin_th * (oy - y) * 0.5;
py = cos_th * (oy - y) * 0.5 - sin_th * (ox - x) * 0.5;
pl = (px * px) / (rx * rx) + (py * py) / (ry * ry);
if (pl > 1) {
pl = Math.sqrt(pl);
rx *= pl;
ry *= pl;
}
a00 = cos_th / rx;
a01 = sin_th / rx;
a10 = (-sin_th) / ry;
a11 = cos_th / ry;
x0 = a00 * ox + a01 * oy;
y0 = a10 * ox + a11 * oy;
x1 = a00 * x + a01 * y;
y1 = a10 * x + a11 * y;
d = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0);
sfactor_sq = 1 / d - 0.25;
if (sfactor_sq < 0) {
sfactor_sq = 0;
}
sfactor = Math.sqrt(sfactor_sq);
if (sweep === large) {
sfactor = -sfactor;
}
xc = 0.5 * (x0 + x1) - sfactor * (y1 - y0);
yc = 0.5 * (y0 + y1) + sfactor * (x1 - x0);
th0 = Math.atan2(y0 - yc, x0 - xc);
th1 = Math.atan2(y1 - yc, x1 - xc);
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;
}
segments = Math.ceil(Math.abs(th_arc / (Math.PI * 0.5 + 0.001)));
result = [];
for (i = j = 0, ref = segments; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {
th2 = th0 + i * th_arc / segments;
th3 = th0 + (i + 1) * th_arc / segments;
result[i] = [xc, yc, th2, th3, rx, ry, sin_th, cos_th];
}
return result;
};
segmentToBezier = function(cx, cy, th0, th1, rx, ry, sin_th, cos_th) {
var a00, a01, a10, a11, t, th_half, x1, x2, x3, y1, y2, y3;
a00 = cos_th * rx;
a01 = -sin_th * ry;
a10 = sin_th * rx;
a11 = cos_th * ry;
th_half = 0.5 * (th1 - th0);
t = (8 / 3) * Math.sin(th_half * 0.5) * Math.sin(th_half * 0.5) / Math.sin(th_half);
x1 = cx + Math.cos(th0) - t * Math.sin(th0);
y1 = cy + Math.sin(th0) + t * Math.cos(th0);
x3 = cx + Math.cos(th1);
y3 = cy + Math.sin(th1);
x2 = x3 + t * Math.sin(th1);
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];
};
return SVGPath;
})();
module.exports = SVGPath;
}).call(this);