简体   繁体   English

如何将(lerp)范围输入线性插值到范围输出?

[英]How do I linearly interpolate (lerp) ranged input to ranged output?

I want to generically interpolate between a range of input values (say, between A and B) and get a range of output values (say, between C and D). 我想在一系列输入值之间进行一般插值(例如,在A和B之间)并获得一系列输出值(例如,在C和D之间)。 Sometimes I want to clamp the value (so that B+10000 still outputs D) and sometimes I don't. 有时我想要钳制值(因此B + 10000仍然输出D),有时我不会。 How do I do it? 我该怎么做?

For example, given input speeds between 20 mph and 80 mph, I want to adjust the zoom level of my map between 17 and 15: 例如,如果输入速度在20英里/小时到80英里/小时之间,我想在17到15之间调整地图的缩放级别:

Without Clamping 没有夹紧

     | \ 
     |  \
 17  |   \
     |    \
     |     \
     |      \
     |       \
 15  |        \
     |         \
     +----------\-
        20  80   \

With Clamping 夹紧

     |
 17  |----
     |    \
     |     \
     |      \
     |       \
 15  |        ----
     |
     +------------
        20  80    

I found this utility function , but (a) it does not support clamping by itself, requiring a second function call, and (b) it only supports input between 0 and 1. 我发现了这个效用函数 ,但是(a)它不支持自身的钳位,需要第二次函数调用,(b)它只支持0到1之间的输入。

The general (unclamped) equation you want is: 你想要的一般(未夹紧)方程是:

var unclamped = (x-minX) * (maxY-minY)/(maxX-minX) + minY;

For clamping, you can either clamp the output after you calculate the result: 对于夹紧,您可以在计算结果后钳制输出:

var clamped = Math.max( minY, Math.min( maxY, unclamped ) );

Or you can clamp the input before you use it: 或者您可以在使用之前钳制输入:

x = Math.max( minX, Math.min( maxX, x ) )
var clamped = (x-minX) * (maxY-minY)/(maxX-minX) + minY;

If the slope of the line does not change, and your clamping desires do not change, you can improve performance by pre-calculating it once and generating a function tailored to your input and needs: 如果线的斜率没有变化,并且您的夹紧要求不会改变,您可以通过预先计算一次并根据您的输入和需求生成一个功能来提高性能:

// Generate a lerp function for a specific set of input/output,
// with or without clamping to the output range.
function lerp(minX, maxX, minY, maxY, clampFlag) {
  var slope = (maxY-minY)/(maxX-minX);
  return clampFlag ?
    function(x){ return ((x<minX?minX:x>maxX?maxX:x) - minX) * slope + minY }
    :
    function(x){ return (x-minX)*slope + minY }
}

In action: 在行动:

 prepPlotter(); // Get ready to draw a pretty graph of the results // Make a simple input/output function var zoomForSpeed = lerp(20, 80, 17, 15, true); for (var speed=0; speed<=99; speed++) { var zoom = zoomForSpeed(speed); // Bam! Lerp'd! plot(speed,zoom); // Proof of the goodness } // Show the min/max input and output ctx.fillStyle = 'red'; plot(20,17,2); plot(80,15,2); function plot(speed,zoom,scale) { ctx.fillRect(speed,zoom,0.5*(scale||1),0.03*(scale||1)); } function prepPlotter() { ctx = document.querySelector('canvas').getContext('2d'); ctx.translate(0,875); ctx.scale(3,-50); } function lerp(minX, maxX, minY, maxY, clampFlag) { var slope = (maxY-minY)/(maxX-minX); return clampFlag ? function(x){ return ((x<minX?minX:x>maxX?maxX:x) - minX) * slope + minY } : function(x){ return (x-minX)*slope + minY } } 
 <canvas>Press "Run code snippet" for a graph of zoomForSpeed</canvas> 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM