clay-core
Version:
Provide a more friendly web-side drawing interface!
79 lines (67 loc) • 2.75 kB
JavaScript
/**
* Cardinal三次插值
* ----------------------------
* Hermite拟合的计算是,确定二个点和二个点的斜率
* 用一个y=ax(3)+bx(2)+cx+d的三次多项式来求解
* 而Cardinal是建立在此基础上
* 给定需要拟合的二个点和第一个点的前一个点+最后一个点的后一个点
* 第一个点的斜率由第一个点的前一个点和第二个点的斜率确定
* 第二个点的斜率由第一个点和第二个点的后一个点的斜率确定
*/
clay.cardinal = function () {
var scope = { "t": 0 };
// 根据x值返回y值
var i;
var cardinal = function (x) {
if (scope.hs) {
i = -1;
// 寻找记录x实在位置的区间
// 这里就是寻找对应的拟合函数
while (i + 1 < scope.hs.x.length && (x > scope.hs.x[i + 1] || (i == -1 && x >= scope.hs.x[i + 1]))) {
i += 1;
}
if (i == -1 || i >= scope.hs.h.length)
throw new Error('Coordinate crossing!');
return scope.hs.h[i](x);
} else {
throw new Error('You shoud first set the position!');
}
};
// 设置张弛系数【应该在点的位置设置前设置】
cardinal.setU = function (t) {
if (_is_number(t)) {
scope.t = t;
} else {
throw new Error('Expecting a figure!');
}
return cardinal;
};
// 设置点的位置
// 参数格式:[[x,y],[x,y],...]
// 至少二个点
cardinal.setP = function (points) {
scope.hs = {
"x": [],
"h": []
};
var flag,
slope = (points[1][1] - points[0][1]) / (points[1][0] - points[0][0]),
temp;
scope.hs.x[0] = points[0][0];
for (flag = 1; flag < points.length; flag++) {
if (points[flag][0] <= points[flag - 1][0]) throw new Error('The point position should be increamented!');
scope.hs.x[flag] = points[flag][0];
// 求点斜率
temp = flag < points.length - 1 ?
(points[flag + 1][1] - points[flag - 1][1]) / (points[flag + 1][0] - points[flag - 1][0]) :
(points[flag][1] - points[flag - 1][1]) / (points[flag][0] - points[flag - 1][0]);
// 求解二个点直接的拟合方程
// 第一个点的前一个点直接取第一个点
// 最后一个点的后一个点直接取最后一个点
scope.hs.h[flag - 1] = clay.hermite().setU(scope.t).setP(points[flag - 1][0], points[flag - 1][1], points[flag][0], points[flag][1], slope, temp);
slope = temp;
}
return cardinal;
};
return cardinal;
};