/**
* @module montage/core/geometry/cubic-bezier
* @requires montage/core/core
* @requires montage/core/geometry/point
*/
var Montage = require("../core").Montage;
var Point = require("./point").Point;
/**
* @class CubicBezier
* @extends Montage
*/
var CubicBezier = exports.CubicBezier = Montage.specialize( /** @lends CubicBezier# */{
/**
* @function
* @param {Array} controlPoints Control points.
* @returns itself
*/
init: {
enumerable: false,
value: function (controlPoints) {
if (controlPoints !== null) {
if (controlPoints.length === 2) {
this.p1 = controlPoints[0];
this.p2 = controlPoints[1];
} else if (controlPoints.length === 4) {
this.p0 = controlPoints[0];
this.p1 = controlPoints[1];
this.p2 = controlPoints[2];
this.p3 = controlPoints[3];
}
}
return this;
}
},
/**
* @function
* @param {number} t Control point.
* @returns itself or `new Point().init(this.p0.x * b1 + this.p1.x * b2 +
* this.p2.x * b3 + this.p3.x * b4, this.p0.y * b1 + this.p1.y * b2 +
* this.p2.y * b3 + this.p3.y * b4)`
*/
position: {
enumerable: false,
value: function (t) {
if (t < 0 || t > 1) {
return;
}
t = 1 - t;
var b1 = t * t * t,
b2 = 3 * t * t * (1 - t),
b3 = 3 * t * (1 - t) * (1 - t),
b4 = (1 - t) * (1 - t) * (1 - t);
return new Point().init(this.p0.x * b1 + this.p1.x * b2 + this.p2.x * b3 + this.p3.x * b4,
this.p0.y * b1 + this.p1.y * b2 + this.p2.y * b3 + this.p3.y * b4);
}
},
/**
* @function
* @param {number} t Control point.
* @returns CubicBezier.create(CubicBezier).init([this.p0, this.p01, this.p012, this.p0123])
*/
split: {
enumerable: false,
value: function (t) {
this.makeScaffolding(t);
return (new CubicBezier()).init([this.p0, this.p01, this.p012, this.p0123]);
}
},
/**
* @function
* @param {number} t Control point.
* @returns `CubicBezier.create(CubicBezier).init([new
* Point().init(this.p01.x / xScale, this.p01.y / yScale), new
* Point().init(this.p012.x / xScale, this.p012.y / yScale)])`
*/
splitToTimingFunction: {
enumerable: false,
value: function (t) {
this.makeScaffolding(t);
// p0123 x and y are the scale
var xScale = this.p0123.x,
yScale = this.p0123.y;
return (new CubicBezier()).init([new Point().init(this.p01.x / xScale, this.p01.y / yScale), new Point().init(this.p012.x / xScale, this.p012.y / yScale)]);
}
},
/**
* @function
* @param {number} t Control point.
*/
makeScaffolding: {
enumerable: false,
value: function (t) {
t = 1 - t;
var precision = 1000000;
Montage.defineProperty(this, 'p01', {
value: Point.interpolate(t, this.p0, this.p1, precision)
});
Montage.defineProperty(this, 'p12', {
value: Point.interpolate(t, this.p1, this.p2, precision)
});
Montage.defineProperty(this, 'p23', {
value: Point.interpolate(t, this.p2, this.p3, precision)
});
Montage.defineProperty(this, 'p012', {
value: Point.interpolate(t, this.p01, this.p12, precision)
});
Montage.defineProperty(this, 'p123', {
value: Point.interpolate(t, this.p12, this.p23, precision)
});
Montage.defineProperty(this, 'p0123', {
value: Point.interpolate(t, this.p012, this.p123, precision)
});
}
},
/**
* First control point in bezier curve.
* @type {Property}
* @default {number} new Point().init(0, 0)
*/
p0: {
enumerable: true,
value: new Point().init(0, 0)
},
/**
* Second control point in bezier curve.
* @type {Property}
* @default {number} new Point().init(0, 0)
*/
p1: {
enumerable: true,
value: new Point().init(0, 0)
},
/**
* Third control point in bezier curve.
* @type {Property}
* @default {number} new Point().init(1, 1)
*/
p2: {
enumerable: true,
value: new Point().init(1, 1)
},
/**
* Fourth control point in bezier curve.
* @type {Property}
* @default {number}M ontage.create(Point).init(1, 1)
*/
p3: {
enumerable: true,
value: new Point().init(1, 1)
}
});