AturSams
AturSams

Reputation: 7952

Calculate the length of a segment of a quadratic bezier

I use this algorithm to calculate the length of a quadratic bezier: http://www.malczak.linuxpl.com/blog/quadratic-bezier-curve-length/

However, what I wish to do is calculate the length of the bezier from 0 to t where 0 < t < 1

Is there any way to modify the formula used in the link above to get the length of the first segment of a bezier curve?

Just to clarify, I'm not looking for the distance between q(0) and q(t) but the length of the arc that goes between these points.

(I don't wish to use adaptive subdivision to aproximate the length)

Upvotes: 9

Views: 11358

Answers (3)

Michael Anderson
Michael Anderson

Reputation: 73470

Since I was sure a similar form solution would exist for that variable t case - I extended the solution given in the link.

Starting from the equation in the link:

L(t)=\int_0^t\sqrt{At^2+Bt+C};dt

Which we can write as

eL(t)=\sqrt{A}\int_0^t\sqrt{t^2+2bt+c};dt

Where b = B/(2A) and c = C/A.

Then transforming u = t + b we get

L=\sqrt{A}\int_{b}^u\sqrt{u^2+k};dt)

Where k = c - b^2

Now we can use the integral identity from the link to obtain:

L=\frac{\sqrt{A}}{2}\left(u\sqrt{u^2+k}-b\sqrt{b^2+k}+k\log\left|\frac{u+\sqrt{u^2+k}}{b+\sqrt{b^2+k}}\right|\right)

So, in summary, the required steps are:

  1. Calculate A,B,C as in the original equation.
  2. Calculate b = B/(2A) and c = C/A
  3. Calculate u = t + b and k = c -b^2
  4. Plug these values into the equation above.

[Edit by Spektre] I just managed to implement this in C++ so here the code (and working correctly matching naively obtained arc lengths):

float x0,x1,x2,y0,y1,y2;      // control points of Bezier curve
float get_l_analytic(float t) // get arclength from parameter t=<0,1>
    {
    float ax,ay,bx,by,A,B,C,b,c,u,k,L;
    ax=x0-x1-x1+x2;
    ay=y0-y1-y1+y2;
    bx=x1+x1-x0-x0;
    by=y1+y1-y0-y0;
    A=4.0*((ax*ax)+(ay*ay));
    B=4.0*((ax*bx)+(ay*by));
    C=     (bx*bx)+(by*by);
    b=B/(2.0*A);
    c=C/A;
    u=t+b;
    k=c-(b*b);
    L=0.5*sqrt(A)*
        (
         (u*sqrt((u*u)+k))
        -(b*sqrt((b*b)+k))
        +(k*log(fabs((u+sqrt((u*u)+k))/(b+sqrt((b*b)+k)))))
        );
    return L;
    }

There is still room for improvement as some terms are computed more than once ...

Upvotes: 10

user1225999
user1225999

Reputation: 920

You just have to evaluate the integral not between 0 and 1 but between 0 and t. You can use the symbolic toolbox of your choice to do that if you're not into the math. For instance:

http://integrals.wolfram.com/index.jsp?expr=Sqrt\[a*x*x%2Bb*x%2Bc\]&random=false

Evaluate the result for x = t and x = 0 and subtract them.

Upvotes: 2

Michael Anderson
Michael Anderson

Reputation: 73470

While there may be a closed form expression, this is what I'd do:

Use De-Casteljau's algorithm to split the bezier into the 0 to t part and use the algorithm from the link to calculate its length.

Upvotes: 2

Related Questions