范围到另一范围的非线性插值

时间:2014-09-09 19:54:48

标签: javascript

我正在努力创建一个函数,将一个范围内插到另一个范围。我已经有了一个正常运行的线性插值,但是它已经变得越来越弯曲了#39;插值,我很难过。

F.ex。我希望以某种方式将范围[0,100]插值到[0,1000],因此接近0的目标值比1000附近的目标值更可能(反之亦然)。

我工作的一种方法是使用对数插值,这有一些恼人的缺点:

  • 我使用粗黑客来处理负数(f.ex。[ - 70,50]),通过在计算前偏移范围
  • '斜坡'不可调节(例如,如果我希望目标值比线性插值更可能或更可能),
  

函数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; 
     

};

我已经阅读了很多关于二次方程的文章,认为这样可以解决我的问题,但从来没有找到一个有效的解决方案。如果我需要进一步解释,请告诉我。

1 个答案:

答案 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) }
};