簡體   English   中英

給定y在貝塞爾曲線上獲得x

[英]Get x on Bezier curve given y

我有一個貝塞爾曲線: (0,0)(.25,.1)(.25,1)(1,1)

可以在此處以圖形方式看到: http : //cubic-bezier.com/#.25,.1,.25,1

我們在x軸上看到的是時間。

這是我的未知數。 這是一個晶胞。 所以我想知道當y為0.5時如何得到x?

謝謝

我看到了這個主題: 給定x立方貝塞爾曲線的y坐標

但是它循環了,我需要避免某些循環,所以我找到了這個主題: 三次貝塞爾曲線-給定X獲得Y

但是我不知道如何在js中解三次多項式:(

從數學上講這是不可能的,除非您可以保證每個x值只有一個y值,即使在單位矩形上也不能(例如,{0,0},{1,0.6},{0,0.4 },{1,1}在中點會很有趣!)。 最快的方法就是簡單地構建一個LUT,例如:

var LUT_x = [], LUT_y = [], t, a, b, c, d;
for(let i=0; i<100; i++) {
  t = i/100;
  a = (1-t)*(1-t)*(1-t);
  b = (1-t)*(1-t)*t;
  c = (1-t)*t*t;
  d = t*t*t;
  LUT_x.push( a*x1 + 3*b*x2 + 3*c*x3 + d*x4 );
  LUT_y.push( a*y1 + 3*b*y2 + 3*c*y3 + d*y4 );
}

完成,現在,如果要在某個y值中查找x值,只需遍歷LUT_y直到找到y值,或者更實際地直到在索引ii+1處找到兩個值以使y值位於某處在它們之間,您將立即知道相應的x值,因為它將在LUT_x中位於相同的索引LUT_x

對於具有2個索引ii+1精確匹配,您只需進行線性插值(即yii+1之間的距離...,對於x坐標,它在ii+1之間的距離相同)

使用查找表的所有解決方案只能給您近似的結果。 如果那對您足夠好,那么您就定了。 如果想要更准確的結果,則需要使用某種數值方法。

對於度數為N的一般貝塞爾曲線,您確實需要循環。 意味着,您需要使用二分法或Newton Raphson方法或類似方法來找到與給定y值相對應的x值,並且這些方法(幾乎)總是涉及從初始猜測開始的迭代。 如果有多種解決方案,那么您獲得的x值將取決於您的初始猜測。

但是,如果只關心三次貝塞爾曲線,則可以使用卡爾達諾公式找到三次多項式的根,因此可以進行解析解。 在OP中引用的此鏈接( 給定x立方貝塞爾曲線的y坐標 )中,Dave Bakker給出了一個答案,該答案顯示了如何使用Cardano公式求解三次多項式。 提供了Javascript中的源代碼。 我認為這將是您開始調查的良好來源。

再次感謝邁克的幫助,我們找到了最快的方法。 我把這個函數放在一起,平均花費0.28msg:

function getValOnCubicBezier_givenXorY(options) {
  /*
  options = {
   cubicBezier: {xs:[x1, x2, x3, x4], ys:[y1, y2, y3, y4]};
   x: NUMBER //this is the known x, if provide this must not provide y, a number for x will be returned
   y: NUMBER //this is the known y, if provide this must not provide x, a number for y will be returned
  }
  */
  if ('x' in options && 'y' in options) {
    throw new Error('cannot provide known x and known y');
  }
  if (!('x' in options) && !('y' in options)) {
    throw new Error('must provide EITHER a known x OR a known y');
  }

  var x1 = options.cubicBezier.xs[0];
  var x2 = options.cubicBezier.xs[1];
  var x3 = options.cubicBezier.xs[2];
  var x4 = options.cubicBezier.xs[3];

  var y1 = options.cubicBezier.ys[0];
  var y2 = options.cubicBezier.ys[1];
  var y3 = options.cubicBezier.ys[2];
  var y4 = options.cubicBezier.ys[3];

  var LUT = {
    x: [],
    y: []
  }

  for(var i=0; i<100; i++) {
    var t = i/100;
    LUT.x.push( (1-t)*(1-t)*(1-t)*x1 + 3*(1-t)*(1-t)*t*x2 + 3*(1-t)*t*t*x3 + t*t*t*x4 );
    LUT.y.push( (1-t)*(1-t)*(1-t)*y1 + 3*(1-t)*(1-t)*t*y2 + 3*(1-t)*t*t*y3 + t*t*t*y4 );
  }

  if ('x' in options) {
    var knw = 'x'; //known
    var unk = 'y'; //unknown
  } else {
    var knw = 'y'; //known
    var unk = 'x'; //unknown
  }

  for (var i=1; i<100; i++) {
    if (options[knw] >= LUT[knw][i] && options[knw] <= LUT[knw][i+1]) {
      var linearInterpolationValue = options[knw] - LUT[knw][i];
      return LUT[unk][i] + linearInterpolationValue;
    }
  }

}

var ease = { //cubic-bezier(0.25, 0.1, 0.25, 1.0)
  xs: [0, .25, .25, 1],
  ys: [0, .1, 1, 1]
};

var linear = {
  xs: [0, 0, 1, 1],
  ys: [0, 0, 1, 1]
};

//console.time('calc');
var x = getValOnCubicBezier_givenXorY({y:.5, cubicBezier:linear});
//console.timeEnd('calc');
//console.log('x:', x);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM