我正在努力创建一个函数,将一个范围内插到另一个范围。我已经有了一个正常运行的线性插值,但是它已经变得越来越弯曲了#39;插值,我很难过。
F.ex。我希望以某种方式将范围[0,100]
插值到[0,1000]
,因此接近0的目标值比1000附近的目标值更可能(反之亦然)。
我工作的一种方法是使用对数插值,这有一些恼人的缺点:
函数logPol(value,s1,s2,t1,t2){
var f = (value - s1) / ((value - s1) + (s2 - value)); var add = 0; if(t1 <= 0 || t2 <= 0) { add = t1 >= t2? 2 * Math.abs(t2) + 1 : 2 * Math.abs(t1) + 1; t1 += add; t2 += add; } var interpolated = Math.pow(t2,f) * Math.pow(t1, 1-f) - add; return interpolated;
};
我已经阅读了很多关于二次方程的文章,认为这样可以解决我的问题,但从来没有找到一个有效的解决方案。如果我需要进一步解释,请告诉我。
答案 0 :(得分:3)
在阅读了大量不同的方法后,我终于解决了我的问题,并最终使用贝塞尔曲线来处理我的插值。这是我的结果:
/**
* Returns a bezier interpolated value, using the given ranges
* @param {number} value Value to be interpolated
* @param {number} s1 Source range start
* @param {number} s2 Source range end
* @param {number} t1 Target range start
* @param {number} t2 Target range end
* @param {number} [slope] Weight of the curve (0.5 = linear, 0.1 = weighted near target start, 0.9 = weighted near target end)
* @returns {number} Interpolated value
*/
var interpolate = function (value, s1, s2, t1, t2, slope) {
//Default to linear interpolation
slope = slope || 0.5;
//If the value is out of the source range, floor to min/max target values
if(value < Math.min(s1, s2)) {
return Math.min(s1, s2) === s1 ? t1 : t2;
}
if(value > Math.max(s1, s2)) {
return Math.max(s1, s2) === s1 ? t1 : t2;
}
//Reverse the value, to make it correspond to the target range (this is a side-effect of the bezier calculation)
value = s2-value;
var C1 = {x: s1, y:t1}; //Start of bezier curve
var C3 = {x: s2, y:t2}; //End of bezier curve
var C2 = { //Control point
x: C3.x,
y: C1.y + Math.abs(slope) * (C3.y - C1.y)
};
//Find out how far the value is on the curve
var percent = value / (C3.x-C1.x);
return C1.y*b1(percent) + C2.y*b2(percent) + C3.y*b3(percent);
function b1(t) { return t*t }
function b2(t) { return 2*t*(1 - t) }
function b3(t) { return (1 - t)*(1 - t) }
};