mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-07-08 10:44:30 -04:00
Switch from using Function#apply() trick for passing curve values as function parameters to simply passing arrays and looking up the values on then.
This commit is contained in:
parent
23f38c6e5b
commit
8606f25542
2 changed files with 73 additions and 88 deletions
src/path
|
@ -229,25 +229,20 @@ var Curve = this.Curve = Base.extend(/** @lends Curve# */{
|
||||||
* @bean
|
* @bean
|
||||||
*/
|
*/
|
||||||
getLength: function(/* from, to */) {
|
getLength: function(/* from, to */) {
|
||||||
|
// Hide parameters from Bootstrap so it injects bean too
|
||||||
var from = arguments[0],
|
var from = arguments[0],
|
||||||
to = arguments[1];
|
to = arguments[1];
|
||||||
fullLength = arguments.length == 0 || from == 0 && to == 1;
|
fullLength = arguments.length == 0 || from == 0 && to == 1;
|
||||||
if (fullLength && this._length != null)
|
if (fullLength && this._length != null)
|
||||||
return this._length;
|
return this._length;
|
||||||
// Hide parameters from Bootstrap so it injects bean too
|
var length = Curve.getLength(this.getValues(), from, to);
|
||||||
var args = this.getValues();
|
|
||||||
if (!fullLength)
|
|
||||||
args.push(from, to);
|
|
||||||
var length = Curve.getLength.apply(Curve, args);
|
|
||||||
if (fullLength)
|
if (fullLength)
|
||||||
this._length = length;
|
this._length = length;
|
||||||
return length;
|
return length;
|
||||||
},
|
},
|
||||||
|
|
||||||
getPart: function(from, to) {
|
getPart: function(from, to) {
|
||||||
var args = this.getValues();
|
return new Curve(Curve.getPart(this.getValues(), from, to));
|
||||||
args.push(from, to);
|
|
||||||
return new Curve(Curve.getPart.apply(Curve, args));
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -270,18 +265,8 @@ var Curve = this.Curve = Base.extend(/** @lends Curve# */{
|
||||||
* @return {Number}
|
* @return {Number}
|
||||||
*/
|
*/
|
||||||
getParameterAt: function(offset, start) {
|
getParameterAt: function(offset, start) {
|
||||||
var args = this.getValues();
|
return Curve.getParameterAt(this.getValues(), offset,
|
||||||
args.push(offset, start !== undefined ? start : offset < 0 ? 1 : 0);
|
start !== undefined ? start : offset < 0 ? 1 : 0);
|
||||||
return Curve.getParameterAt.apply(Curve, args);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Private method used in getPoint, getTangent, getNormal.
|
|
||||||
*/
|
|
||||||
_evaluate: function(parameter, type) {
|
|
||||||
var args = this.getValues();
|
|
||||||
args.push(parameter, type);
|
|
||||||
return Curve.evaluate.apply(Curve, args);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -292,7 +277,7 @@ var Curve = this.Curve = Base.extend(/** @lends Curve# */{
|
||||||
* @return {Point}
|
* @return {Point}
|
||||||
*/
|
*/
|
||||||
getPoint: function(parameter) {
|
getPoint: function(parameter) {
|
||||||
return this._evaluate(parameter, 0);
|
return Curve.evaluate(this.getValues(), parameter, 0);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -302,7 +287,7 @@ var Curve = this.Curve = Base.extend(/** @lends Curve# */{
|
||||||
* point as a value between {@code 0} and {@code 1}.
|
* point as a value between {@code 0} and {@code 1}.
|
||||||
*/
|
*/
|
||||||
getTangent: function(parameter) {
|
getTangent: function(parameter) {
|
||||||
return this._evaluate(parameter, 1);
|
return Curve.evaluate(this.getValues(), parameter, 1);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -312,7 +297,7 @@ var Curve = this.Curve = Base.extend(/** @lends Curve# */{
|
||||||
* point as a value between {@code 0} and {@code 1}.
|
* point as a value between {@code 0} and {@code 1}.
|
||||||
*/
|
*/
|
||||||
getNormal: function(parameter) {
|
getNormal: function(parameter) {
|
||||||
return this._evaluate(parameter, 2);
|
return Curve.evaluate(this.getValues(), parameter, 2);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -320,10 +305,8 @@ var Curve = this.Curve = Base.extend(/** @lends Curve# */{
|
||||||
* @return {Number}
|
* @return {Number}
|
||||||
*/
|
*/
|
||||||
getParameter: function(point) {
|
getParameter: function(point) {
|
||||||
var args = this.getValues();
|
point = Point.read(point);
|
||||||
if (point)
|
return Curve.getParameter(this.getValues(), point.x, point.y);
|
||||||
args.push(point.x, point.y);
|
|
||||||
return Curve.getParameter.apply(Curve, args);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
getCrossings: function(point, matrix) {
|
getCrossings: function(point, matrix) {
|
||||||
|
@ -332,8 +315,7 @@ var Curve = this.Curve = Base.extend(/** @lends Curve# */{
|
||||||
// Solve the y-axis cubic polynominal for point.y and count all
|
// Solve the y-axis cubic polynominal for point.y and count all
|
||||||
// solutions to the right of point.x as crossings.
|
// solutions to the right of point.x as crossings.
|
||||||
var vals = this.getValues(matrix),
|
var vals = this.getValues(matrix),
|
||||||
roots = Curve.solveCubic(vals[1], vals[3], vals[5], vals[7],
|
roots = Curve.solveCubic(vals, 1, point.y),
|
||||||
point.y),
|
|
||||||
crossings = 0;
|
crossings = 0;
|
||||||
for (var i = 0, l = roots != Infinity && roots.length; i < l; i++) {
|
for (var i = 0, l = roots != Infinity && roots.length; i < l; i++) {
|
||||||
var t = roots[i];
|
var t = roots[i];
|
||||||
|
@ -415,8 +397,12 @@ var Curve = this.Curve = Base.extend(/** @lends Curve# */{
|
||||||
: coords;
|
: coords;
|
||||||
},
|
},
|
||||||
|
|
||||||
evaluate: function(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t, type) {
|
evaluate: function(v, t, type) {
|
||||||
var x, y;
|
var p1x = v[0], p1y = v[1],
|
||||||
|
c1x = v[2], c1y = v[3],
|
||||||
|
c2x = v[4], c2y = v[5],
|
||||||
|
p2x = v[6], p2y = v[7],
|
||||||
|
x, y;
|
||||||
|
|
||||||
// Handle special case at beginning / end of curve
|
// Handle special case at beginning / end of curve
|
||||||
// PORT: Change in Sg too, so 0.000000000001 won't be
|
// PORT: Change in Sg too, so 0.000000000001 won't be
|
||||||
|
@ -489,26 +475,24 @@ var Curve = this.Curve = Base.extend(/** @lends Curve# */{
|
||||||
return type == 2 ? new Point(y, -x) : new Point(x, y);
|
return type == 2 ? new Point(y, -x) : new Point(x, y);
|
||||||
},
|
},
|
||||||
|
|
||||||
subdivide: function(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) {
|
subdivide: function(v, t) {
|
||||||
|
var p1x = v[0], p1y = v[1],
|
||||||
|
c1x = v[2], c1y = v[3],
|
||||||
|
c2x = v[4], c2y = v[5],
|
||||||
|
p2x = v[6], p2y = v[7];
|
||||||
if (t === undefined)
|
if (t === undefined)
|
||||||
t = 0.5;
|
t = 0.5;
|
||||||
// Triangle computation, with loops unrolled.
|
// Triangle computation, with loops unrolled.
|
||||||
var u = 1 - t,
|
var u = 1 - t,
|
||||||
// Interpolate from 4 to 3 points
|
// Interpolate from 4 to 3 points
|
||||||
p3x = u * p1x + t * c1x,
|
p3x = u * p1x + t * c1x, p3y = u * p1y + t * c1y,
|
||||||
p3y = u * p1y + t * c1y,
|
p4x = u * c1x + t * c2x, p4y = u * c1y + t * c2y,
|
||||||
p4x = u * c1x + t * c2x,
|
p5x = u * c2x + t * p2x, p5y = u * c2y + t * p2y,
|
||||||
p4y = u * c1y + t * c2y,
|
|
||||||
p5x = u * c2x + t * p2x,
|
|
||||||
p5y = u * c2y + t * p2y,
|
|
||||||
// Interpolate from 3 to 2 points
|
// Interpolate from 3 to 2 points
|
||||||
p6x = u * p3x + t * p4x,
|
p6x = u * p3x + t * p4x, p6y = u * p3y + t * p4y,
|
||||||
p6y = u * p3y + t * p4y,
|
p7x = u * p4x + t * p5x, p7y = u * p4y + t * p5y,
|
||||||
p7x = u * p4x + t * p5x,
|
|
||||||
p7y = u * p4y + t * p5y,
|
|
||||||
// Interpolate from 2 points to 1 point
|
// Interpolate from 2 points to 1 point
|
||||||
p8x = u * p6x + t * p7x,
|
p8x = u * p6x + t * p7x, p8y = u * p6y + t * p7y;
|
||||||
p8y = u * p6y + t * p7y;
|
|
||||||
// We now have all the values we need to build the subcurves:
|
// We now have all the values we need to build the subcurves:
|
||||||
return [
|
return [
|
||||||
[p1x, p1y, p3x, p3y, p6x, p6y, p8x, p8y], // left
|
[p1x, p1y, p3x, p3y, p6x, p6y, p8x, p8y], // left
|
||||||
|
@ -518,18 +502,20 @@ var Curve = this.Curve = Base.extend(/** @lends Curve# */{
|
||||||
|
|
||||||
// Converts from the point coordinates (p1, c1, c2, p2) for one axis to
|
// Converts from the point coordinates (p1, c1, c2, p2) for one axis to
|
||||||
// the polynomial coefficients and solves the polynomial for val
|
// the polynomial coefficients and solves the polynomial for val
|
||||||
solveCubic: function (p1, c1, c2, p2, val) {
|
solveCubic: function (v, coord, val) {
|
||||||
return Numerical.solveCubic(
|
var p1 = v[coord],
|
||||||
p2 - p1 + 3 * (c1 - c2), // a
|
c1 = v[coord + 2],
|
||||||
3 * (c2 + p1) - 6 * c1, // b
|
c2 = v[coord + 4],
|
||||||
3 * (c1 - p1), // c
|
p2 = v[coord + 6],
|
||||||
p1 - val, // d
|
c = 3 * (c1 - p1),
|
||||||
Numerical.TOLERANCE);
|
b = 3 * (c2 - c1) - c,
|
||||||
|
a = p2 - p1 - c - b;
|
||||||
|
return Numerical.solveCubic(a, b, c, p1 - val, Numerical.TOLERANCE);
|
||||||
},
|
},
|
||||||
|
|
||||||
getParameter: function(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, x, y) {
|
getParameter: function(v, x, y) {
|
||||||
var txs = Curve.solveCubic(p1x, c1x, c2x, p2x, x),
|
var txs = Curve.solveCubic(v, 0, x),
|
||||||
tys = Curve.solveCubic(p1y, c1y, c2y, p2y, y),
|
tys = Curve.solveCubic(v, 1, y),
|
||||||
sx = txs === Infinity ? -1 : txs.length,
|
sx = txs === Infinity ? -1 : txs.length,
|
||||||
sy = tys === Infinity ? -1 : tys.length,
|
sy = tys === Infinity ? -1 : tys.length,
|
||||||
tx, ty;
|
tx, ty;
|
||||||
|
@ -560,31 +546,28 @@ var Curve = this.Curve = Base.extend(/** @lends Curve# */{
|
||||||
},
|
},
|
||||||
|
|
||||||
// TODO: Find better name
|
// TODO: Find better name
|
||||||
getPart: function(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, from, to) {
|
getPart: function(v, from, to) {
|
||||||
var curve = [p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y];
|
if (from > 0)
|
||||||
if (from > 0) {
|
v = Curve.subdivide(v, from)[1]; // [1] right
|
||||||
// 8th argument of Curve.subdivide() == t, and values can be
|
// Interpolate the parameter at 'to' in the new curve and
|
||||||
// directly used as arguments list for apply().
|
// cut there.
|
||||||
curve[8] = from;
|
if (to < 1)
|
||||||
curve = Curve.subdivide.apply(Curve, curve)[1]; // right
|
v = Curve.subdivide(v, (to - from) / (1 - from))[0]; // [0] left
|
||||||
}
|
return v;
|
||||||
if (to < 1) {
|
|
||||||
// Se above about curve[8].
|
|
||||||
// Interpolate the parameter at 'to' in the new curve and
|
|
||||||
// cut there
|
|
||||||
curve[8] = (to - from) / (1 - from);
|
|
||||||
curve = Curve.subdivide.apply(Curve, curve)[0]; // left
|
|
||||||
}
|
|
||||||
return curve;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
isFlatEnough: function(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) {
|
isFlatEnough: function(v) {
|
||||||
// Code from Nearest Point-on-Curve Problem and by Philip J.
|
// Code from Nearest Point-on-Curve Problem and by Philip J.
|
||||||
// Schneider from "Graphics Gems", Academic Press, 1990, adapted
|
// Schneider from "Graphics Gems", Academic Press, 1990, adapted
|
||||||
// and optimised for cubic bezier curves.
|
// and optimised for cubic bezier curves.
|
||||||
// Derive the implicit equation for line connecting first and last
|
// Derive the implicit equation for line connecting first and last
|
||||||
// control points
|
// control points
|
||||||
var a = p1y - p2y,
|
var p1x = v[0], p1y = v[1],
|
||||||
|
c1x = v[2], c1y = v[3],
|
||||||
|
c2x = v[4], c2y = v[5],
|
||||||
|
p2x = v[6], p2y = v[7],
|
||||||
|
|
||||||
|
a = p1y - p2y,
|
||||||
b = p2x - p1x,
|
b = p2x - p1x,
|
||||||
c = p1x * p2y - p2x * p1y,
|
c = p1x * p2y - p2x * p1y,
|
||||||
// Find the largest distance from each of the points to the line
|
// Find the largest distance from each of the points to the line
|
||||||
|
@ -632,9 +615,14 @@ var Curve = this.Curve = Base.extend(/** @lends Curve# */{
|
||||||
}
|
}
|
||||||
}, new function() { // Scope for methods that require numerical integration
|
}, new function() { // Scope for methods that require numerical integration
|
||||||
|
|
||||||
function getLengthIntegrand(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) {
|
function getLengthIntegrand(v) {
|
||||||
// Calculate the coefficients of a Bezier derivative.
|
// Calculate the coefficients of a Bezier derivative.
|
||||||
var ax = 9 * (c1x - c2x) + 3 * (p2x - p1x),
|
var p1x = v[0], p1y = v[1],
|
||||||
|
c1x = v[2], c1y = v[3],
|
||||||
|
c2x = v[4], c2y = v[5],
|
||||||
|
p2x = v[6], p2y = v[7],
|
||||||
|
|
||||||
|
ax = 9 * (c1x - c2x) + 3 * (p2x - p1x),
|
||||||
bx = 6 * (p1x + c2x) - 12 * c1x,
|
bx = 6 * (p1x + c2x) - 12 * c1x,
|
||||||
cx = 3 * (c1x - p1x),
|
cx = 3 * (c1x - p1x),
|
||||||
|
|
||||||
|
@ -661,24 +649,23 @@ var Curve = this.Curve = Base.extend(/** @lends Curve# */{
|
||||||
return {
|
return {
|
||||||
statics: true,
|
statics: true,
|
||||||
|
|
||||||
getLength: function(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, a, b) {
|
getLength: function(v, a, b) {
|
||||||
if (a === undefined)
|
if (a === undefined)
|
||||||
a = 0;
|
a = 0;
|
||||||
if (b === undefined)
|
if (b === undefined)
|
||||||
b = 1;
|
b = 1;
|
||||||
if (p1x == c1x && p1y == c1y && p2x == c2x && p2y == c2y) {
|
// if (p1 == c1 && p2 == c2):
|
||||||
|
if (v[0] == v[2] && v[1] == v[3] && v[6] == v[4] && v[7] == v[5]) {
|
||||||
// Straight line
|
// Straight line
|
||||||
var dx = p2x - p1x,
|
var dx = p2x - p1x,
|
||||||
dy = p2y - p1y;
|
dy = p2y - p1y;
|
||||||
return (b - a) * Math.sqrt(dx * dx + dy * dy);
|
return (b - a) * Math.sqrt(dx * dx + dy * dy);
|
||||||
}
|
}
|
||||||
var ds = getLengthIntegrand(
|
var ds = getLengthIntegrand(v);
|
||||||
p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y);
|
|
||||||
return Numerical.integrate(ds, a, b, getIterations(a, b));
|
return Numerical.integrate(ds, a, b, getIterations(a, b));
|
||||||
},
|
},
|
||||||
|
|
||||||
getParameterAt: function(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y,
|
getParameterAt: function(v, offset, start) {
|
||||||
offset, start) {
|
|
||||||
if (offset == 0)
|
if (offset == 0)
|
||||||
return start;
|
return start;
|
||||||
// See if we're going forward or backward, and handle cases
|
// See if we're going forward or backward, and handle cases
|
||||||
|
@ -689,8 +676,7 @@ var Curve = this.Curve = Base.extend(/** @lends Curve# */{
|
||||||
offset = Math.abs(offset),
|
offset = Math.abs(offset),
|
||||||
// Use integrand to calculate both range length and part
|
// Use integrand to calculate both range length and part
|
||||||
// lengths in f(t) below.
|
// lengths in f(t) below.
|
||||||
ds = getLengthIntegrand(
|
ds = getLengthIntegrand(v),
|
||||||
p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y),
|
|
||||||
// Get length of total range
|
// Get length of total range
|
||||||
rangeLength = Numerical.integrate(ds, a, b,
|
rangeLength = Numerical.integrate(ds, a, b,
|
||||||
getIterations(a, b));
|
getIterations(a, b));
|
||||||
|
|
|
@ -51,8 +51,8 @@ var PathFlattener = Base.extend({
|
||||||
_computeParts: function(curve, index, minT, maxT) {
|
_computeParts: function(curve, index, minT, maxT) {
|
||||||
// Check if the t-span is big enough for subdivision.
|
// Check if the t-span is big enough for subdivision.
|
||||||
// We're not subdividing more than 32 times...
|
// We're not subdividing more than 32 times...
|
||||||
if ((maxT - minT) > 1 / 32 && !Curve.isFlatEnough.apply(Curve, curve)) {
|
if ((maxT - minT) > 1 / 32 && !Curve.isFlatEnough(curve)) {
|
||||||
var curves = Curve.subdivide.apply(Curve, curve);
|
var curves = Curve.subdivide(curve);
|
||||||
var halfT = (minT + maxT) / 2;
|
var halfT = (minT + maxT) / 2;
|
||||||
// Recursively subdive and compute parts again.
|
// Recursively subdive and compute parts again.
|
||||||
this._computeParts(curves[0], index, minT, halfT);
|
this._computeParts(curves[0], index, minT, halfT);
|
||||||
|
@ -114,17 +114,16 @@ var PathFlattener = Base.extend({
|
||||||
|
|
||||||
evaluate: function(offset, type) {
|
evaluate: function(offset, type) {
|
||||||
var param = this.getParameterAt(offset);
|
var param = this.getParameterAt(offset);
|
||||||
return Curve.evaluate.apply(Curve,
|
return Curve.evaluate(this.curves[param.index], param.value, type);
|
||||||
this.curves[param.index].concat([param.value, type]));
|
|
||||||
},
|
},
|
||||||
|
|
||||||
drawPart: function(ctx, from, to) {
|
drawPart: function(ctx, from, to) {
|
||||||
from = this.getParameterAt(from);
|
from = this.getParameterAt(from);
|
||||||
to = this.getParameterAt(to);
|
to = this.getParameterAt(to);
|
||||||
for (var i = from.index; i <= to.index; i++) {
|
for (var i = from.index; i <= to.index; i++) {
|
||||||
var curve = Curve.getPart.apply(Curve, this.curves[i].concat(
|
var curve = Curve.getPart(this.curves[i],
|
||||||
i == from.index ? from.value : 0,
|
i == from.index ? from.value : 0,
|
||||||
i == to.index ? to.value : 1));
|
i == to.index ? to.value : 1);
|
||||||
if (i == from.index)
|
if (i == from.index)
|
||||||
ctx.moveTo(curve[0], curve[1]);
|
ctx.moveTo(curve[0], curve[1]);
|
||||||
ctx.bezierCurveTo.apply(ctx, curve.slice(2));
|
ctx.bezierCurveTo.apply(ctx, curve.slice(2));
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue