CurveUtil.js revision 82d0cf8c731b23f6a2fbb31e3e696e629444363e
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp/**
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp * Utility class used for calculating curve points.
82d0cf8c731b23f6a2fbb31e3e696e629444363eTripp *
82d0cf8c731b23f6a2fbb31e3e696e629444363eTripp * @class CurveUtil
82d0cf8c731b23f6a2fbb31e3e696e629444363eTripp * @constructor
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp */
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTrippfunction CurveUtil()
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp{
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp}
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTrippCurveUtil.prototype = {
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp /**
82d0cf8c731b23f6a2fbb31e3e696e629444363eTripp * Creates an array of start, end and control points for splines.
82d0cf8c731b23f6a2fbb31e3e696e629444363eTripp *
82d0cf8c731b23f6a2fbb31e3e696e629444363eTripp * @param {Array} xcoords Collection of x-coordinates used for calculate the curves
82d0cf8c731b23f6a2fbb31e3e696e629444363eTripp * @param {Array} ycoords Collection of y-coordinates used for calculate the curves
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp * @return {Object}
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp */
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp getCurveControlPoints: function(xcoords, ycoords)
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp {
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp var outpoints = [],
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp i = 1,
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp l = xcoords.length - 1,
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp xvals = [],
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp yvals = [];
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp // Too few points, need at least two
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp if (l < 1)
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp {
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp return null;
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp }
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp outpoints[0] = {
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp startx: xcoords[0],
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp starty: ycoords[0],
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp endx: xcoords[1],
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp endy: ycoords[1]
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp };
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp // Special case, the Bezier should be a straight line
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp if (l === 1)
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp {
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp outpoints[0].ctrlx1 = (2.0*xcoords[0] + xcoords[1])/3.0;
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp outpoints[0].ctrly2 = (2.0*ycoords[0] + ycoords[1])/3.0;
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp outpoints[0].ctrlx2 = 2.0*outpoints[0].ctrlx1 - xcoords[0];
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp outpoints[0].ctrly2 = 2.0*outpoints[0].ctrly1 - ycoords[0];
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp return outpoints;
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp }
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp for (; i < l; ++i)
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp {
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp outpoints.push({startx: Math.round(xcoords[i]), starty: Math.round(ycoords[i]), endx: Math.round(xcoords[i+1]), endy: Math.round(ycoords[i+1])});
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp xvals[i] = 4.0 * xcoords[i] + 2*xcoords[i+1];
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp yvals[i] = 4.0*ycoords[i] + 2*ycoords[i+1];
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp }
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp xvals[0] = xcoords[0] + (2.0 * xcoords[1]);
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp xvals[l-1] = (8.0 * xcoords[l-1] + xcoords[l]) / 2.0;
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp xvals = this.getControlPoints(xvals.concat());
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp yvals[0] = ycoords[0] + (2.0 * ycoords[1]);
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp yvals[l-1] = (8.0 * ycoords[l-1] + ycoords[l]) / 2.0;
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp yvals = this.getControlPoints(yvals.concat());
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp for (i = 0; i < l; ++i)
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp {
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp outpoints[i].ctrlx1 = Math.round(xvals[i]);
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp outpoints[i].ctrly1 = Math.round(yvals[i]);
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp if (i < l-1)
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp {
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp outpoints[i].ctrlx2 = Math.round(2*xcoords[i+1] - xvals[i+1]);
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp outpoints[i].ctrly2 = Math.round(2*ycoords[i+1] - yvals[i+1]);
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp }
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp else
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp {
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp outpoints[i].ctrlx2 = Math.round((xcoords[l] + xvals[l-1])/2);
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp outpoints[i].ctrly2 = Math.round((ycoords[l] + yvals[l-1])/2);
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp }
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp }
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp return outpoints;
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp },
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp /**
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp * @private
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp */
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp getControlPoints: function(vals)
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp {
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp var l = vals.length,
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp x = [],
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp tmp = [],
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp b = 2.0,
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp i = 1;
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp x[0] = vals[0] / b;
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp for (; i < l; ++i)
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp {
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp tmp[i] = 1/b;
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp b = (i < l-1 ? 4.0 : 3.5) - tmp[i];
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp x[i] = (vals[i] - x[i-1]) / b;
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp }
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp for (i = 1; i < l; ++i)
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp {
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp x[l-i-1] -= tmp[l-i] * x[l-i];
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp }
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp return x;
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp }
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp};
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTrippY.CurveUtil = CurveUtil;