Javascript 从一个范围到另一个范围的非线性插值
我正在努力创建一个函数,将一个范围插值到另一个范围。我已经有了一个有效的线性插值,但是得到更多的“曲线”插值,我被难住了 F.ex。我想以某种方式将范围Javascript 从一个范围到另一个范围的非线性插值,javascript,Javascript,我正在努力创建一个函数,将一个范围插值到另一个范围。我已经有了一个有效的线性插值,但是得到更多的“曲线”插值,我被难住了 F.ex。我想以某种方式将范围[0100]插值到[01000],因此接近0的目标值比接近1000的目标值更有可能(反之亦然) 我采用的一种方法是使用对数插值,它有一些恼人的缺点: 我使用了一种粗糙的方法来处理负数(f.ex.[-70,50]),方法是在计算前抵消范围 “斜率”是不可调整的(例如,如果我希望目标值比线性插值更可能或更可能) 函数logPol(值s1、s2、t
[0100]
插值到[01000]
,因此接近0的目标值比接近1000的目标值更有可能(反之亦然)
我采用的一种方法是使用对数插值,它有一些恼人的缺点:
- 我使用了一种粗糙的方法来处理负数(f.ex.[-70,50]),方法是在计算前抵消范围
- “斜率”是不可调整的(例如,如果我希望目标值比线性插值更可能或更可能)
var f=(value-s1)/(value-s1)+(s2-value));
var-add=0;
if(t1在阅读了大量不同的方法之后,我最终解决了我的问题,并最终使用Bezier曲线来处理插值。下面是我的结果函数:
/**
* 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) }
};
/**
*使用给定的范围返回贝塞尔插值
*@param{number}要插值的值
*@param{number}s1源范围开始
*@param{number}s2源范围结束
*@param{number}t1目标范围开始
*@param{number}t2目标范围结束
*@param{number}[slope]曲线的权重(0.5=线性,0.1=加权接近目标起点,0.9=加权接近目标终点)
*@返回{number}插值
*/
var插值=函数(值,s1,s2,t1,t2,斜率){
//默认为线性插值
坡度=坡度| | 0.5;
//如果该值不在源范围内,请将下限值设置为最小/最大目标值
如果(值<数学最小值(s1,s2)){
返回数学最小值(s1,s2)==s1?t1:t2;
}
如果(值>数学最大值(s1、s2)){
返回数学最大值(s1,s2)==s1?t1:t2;
}
//反转该值,使其对应于目标范围(这是贝塞尔计算的副作用)
值=s2值;
var C1={x:s1,y:t1};//贝塞尔曲线的起点
var C3={x:s2,y:t2};//贝塞尔曲线的终点
变量C2={//控制点
x:C3.x,
y:C1.y+Math.abs(斜率)*(C3.y-C1.y)
};
//找出值在曲线上的距离
风险值百分比=价值/(C3.x-C1.x);
返回C1.y*b1(百分比)+C2.y*b2(百分比)+C3.y*b3(百分比);
函数b1(t){返回t*t}
函数b2(t){返回2*t*(1-t)}
函数b3(t){返回(1-t)*(1-t)}
};
在阅读了大量不同的方法之后,我终于解决了我的问题,并最终使用贝塞尔曲线来处理插值。下面是我的结果函数:
/**
* 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) }
};
/**
*使用给定的范围返回贝塞尔插值
*@param{number}要插值的值
*@param{number}s1源范围开始
*@param{number}s2源范围结束
*@param{number}t1目标范围开始
*@param{number}t2目标范围结束
*@param{number}[slope]曲线的权重(0.5=线性,0.1=加权接近目标起点,0.9=加权接近目标终点)
*@返回{number}插值
*/
var插值=函数(值,s1,s2,t1,t2,斜率){
//默认为线性插值
坡度=坡度| | 0.5;
//如果该值不在源范围内,请将下限值设置为最小/最大目标值
如果(值<数学最小值(s1,s2)){
返回数学最小值(s1,s2)==s1?t1:t2;
}
如果(值>数学最大值(s1、s2)){
返回数学最大值(s1,s2)==s1?t1:t2;
}
//反转该值,使其对应于目标范围(这是贝塞尔计算的副作用)
值=s2值;
var C1={x:s1,y:t1};//贝塞尔曲线的起点
var C3={x:s2,y:t2};//贝塞尔曲线的终点
变量C2={//控制点
x:C3.x,
y:C1.y+Math.abs(斜率)*(C3.y-C1.y)
};
//找出值在曲线上的距离
风险值百分比=价值/(C3.x-C1.x);
返回C1.y*b1(百分比)+C2.y*b2(百分比)+C3.y*b3(百分比);
函数b1(t){返回t*t}
函数b2(t){返回2*t*(1-t)}
函数b3(t){返回(1-t)*(1-t)}
};
您不是在寻找插值,而是在寻找映射?如果您不知道如何计算,那么您就错了,因为它与JavaScript(或任何其他语言)编程完全无关。你应该看看d3,它能做你想要的一切和更多。你不是在找插值,而是在找映射?如果你不知道如何做数学,你就错了,因为它与JavaScript(或任何其他语言)编程完全无关。你应该看看d3,它能做你想要的一切和更多。