Cubic Bezier reverse GetPoint equation: float for Vector <=> Vector for float

百般思念 提交于 2019-12-20 04:32:46

问题


Is it possible to get float t back given the resulting value and the four points? If so, how?

public static Vector3 GetPoint (Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t) {
    t = Mathf.Clamp01(t);
    float oneMinusT = 1f - t;
    return
        oneMinusT * oneMinusT * oneMinusT * p0 +
        3f * oneMinusT * oneMinusT * t * p1 +
        3f * oneMinusT * t * t * p2 +
        t * t * t * p3;
}

Code from this Tutorial by Jasper Flick


回答1:


It is, and involves implementing root finding for third degree functions. One direct way of doing that is to implement Cardano's Algorithm for finding the roots for a polynomial of degree three - a JavaScript implementation of that can be found here. Depending on the curve's parameters, you will get up to three equally correcet answers, so depending on what you were trying to find the t value for, you'll have to do more work to find out which of those up-to-three values you need.

// Not in every toolbox, so: how to implement the cubic root
// equivalent of the sqrt function (note that there are actually
// three roots: one real, two complex, and we don't care about the latter):
function crt(v) { if (v<0) return -pow(-v,1/3); return pow(v,1/3); } 

// Cardano's algorithm, based on
// http://www.trans4mind.com/personal_development/mathematics/polynomials/cubicAlgebra.htm
function cardano(curve, line) {
  // align curve with the intersecting line, translating/rotating
  // so that the first point becomes (0,0), and the last point
  // ends up lying on the line we're trying to use as root-intersect.
  var aligned = align(curve, line),
      // rewrite from [a(1-t)^3 + 3bt(1-t)^2 + 3c(1-t)t^2 + dt^3] form...
      pa = aligned[0].y,
      pb = aligned[1].y,
      pc = aligned[2].y,
      pd = aligned[3].y,
      // ...to [t^3 + at^2 + bt + c] form:
      d = (  -pa + 3*pb - 3*pc + pd),
      a = ( 3*pa - 6*pb + 3*pc) / d,
      b = (-3*pa + 3*pb) / d,
      c = pa / d,
      // then, determine p and q:
      p = (3*b - a*a)/3,
      p3 = p/3,
      q = (2*a*a*a - 9*a*b + 27*c)/27,
      q2 = q/2, 
      // and determine the discriminant:
      discriminant = q2*q2 + p3*p3*p3,
      // and some reserved variables for later
      u1,v1,x1,x2,x3;

  // If the discriminant is negative, use polar coordinates
  // to get around square roots of negative numbers
  if (discriminant < 0) {
    var mp3 = -p/3,
        mp33 = mp3*mp3*mp3,
        r = sqrt( mp33 ),
        t = -q/(2*r),
        // deal with IEEE rounding yielding <-1 or >1
        cosphi = t<-1 ? -1 : t>1 ? 1 : t,
        phi = acos(cosphi),
        crtr = crt(r),
        t1 = 2*crtr;
    x1 = t1 * cos(phi/3) - a/3;
    x2 = t1 * cos((phi+tau)/3) - a/3;
    x3 = t1 * cos((phi+2*tau)/3) - a/3;
    return [x1, x2, x3];
  }

  else if(discriminant === 0) {
    u1 = q2 < 0 ? crt(-q2) : -crt(q2);
    x1 = 2*u1-a/3;
    x2 = -u1 - a/3;
    return [x1,x2];
  }

  // one real root, and two imaginary roots
  else {
    var sd = sqrt(discriminant),
        tt = -q2+sd;
    u1 = crt(-q2+sd);
    v1 = crt(q2+sd);
    x1 =  u1 - v1 - a/3;
    return [x1];
  }
}



回答2:


Solving the following cubic polynomial should reveal your original t:

(p3 - (3 * p2) + (3 * p1) - p0) * t^3
+ ((3 * p2) - (6 * p1) + (3 * p0)) * t^2
+ ((3 * p1) - (3 * p0)) * t
+ p0
= 0

I put it in standard form so you could easily get the roots from the coefficients.



来源:https://stackoverflow.com/questions/26823024/cubic-bezier-reverse-getpoint-equation-float-for-vector-vector-for-float

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!