Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
561 views
in Technique[技术] by (71.8m points)

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

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

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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];
  }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...