Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calculating the bounding box of cubic bezier curve

I am trying to find an algorithm to calculate the bounding box of a given cubic bezier curve. The curve is in 3D space.

Is there a mathematic way to do this except of sampling points on the curve and calculating the bounding box of these points?

like image 603
Erik Sapir Avatar asked Jul 17 '14 17:07

Erik Sapir


3 Answers

this article explain the details and also has a live html5 demo:
Calculating / Computing the Bounding Box of Cubic Bezier

I found a javascript in Snap.svg to calculate that: here
see the bezierBBox and curveDim functions.

I rewrite a javascript function.

//(x0,y0) is start point; (x1,y1),(x2,y2) is control points; (x3,y3) is end point.
function bezierMinMax(x0, y0, x1, y1, x2, y2, x3, y3) {
    var tvalues = [], xvalues = [], yvalues = [],
        a, b, c, t, t1, t2, b2ac, sqrtb2ac;
    for (var i = 0; i < 2; ++i) {
        if (i == 0) {
            b = 6 * x0 - 12 * x1 + 6 * x2;
            a = -3 * x0 + 9 * x1 - 9 * x2 + 3 * x3;
            c = 3 * x1 - 3 * x0;
        } else {
            b = 6 * y0 - 12 * y1 + 6 * y2;
            a = -3 * y0 + 9 * y1 - 9 * y2 + 3 * y3;
            c = 3 * y1 - 3 * y0;
        }
        if (Math.abs(a) < 1e-12) {
            if (Math.abs(b) < 1e-12) {
                continue;
            }
            t = -c / b;
            if (0 < t && t < 1) {
                tvalues.push(t);
            }
            continue;
        }
        b2ac = b * b - 4 * c * a;
        if (b2ac < 0) {
            if (Math.abs(b2ac) < 1e-12) {
                t = -b / (2 * a);
                if (0 < t && t < 1) {
                    tvalues.push(t);
                }
            }
            continue;
        }
        sqrtb2ac = Math.sqrt(b2ac);
        t1 = (-b + sqrtb2ac) / (2 * a);
        if (0 < t1 && t1 < 1) {
            tvalues.push(t1);
        }
        t2 = (-b - sqrtb2ac) / (2 * a);
        if (0 < t2 && t2 < 1) {
            tvalues.push(t2);
        }
    }

    var j = tvalues.length, mt;
    while (j--) {
        t = tvalues[j];
        mt = 1 - t;
        xvalues[j] = (mt * mt * mt * x0) + (3 * mt * mt * t * x1) + (3 * mt * t * t * x2) + (t * t * t * x3);
        yvalues[j] = (mt * mt * mt * y0) + (3 * mt * mt * t * y1) + (3 * mt * t * t * y2) + (t * t * t * y3);
    }

    xvalues.push(x0,x3);
    yvalues.push(y0,y3);

    return {
        min: {x: Math.min.apply(0, xvalues), y: Math.min.apply(0, yvalues)},
        max: {x: Math.max.apply(0, xvalues), y: Math.max.apply(0, yvalues)}
    };
}
like image 107
cuixiping Avatar answered Sep 19 '22 17:09

cuixiping


Finding the bounding box of a cubic Bezier curve (or even B-spline curve of any degree) is typically done by finding the bounding box of the curve's control polygon. Since the curve is always bounded by its control polygon, the bounding box obtained via the control polygon is guaranteed to enclose the curve. You can also perform knot insertion to the curve and make the control polygon become closer to the curve itself. So, the general algorithm will go like this:

1) Find the bounding box (denoted as BBox1) of the current B-spline curve from its control polygon.
2) Insert knot at the mid-parameter of each Bezier segment in the B-spline curve.
3) Find the bounding box (denoted as BBox2) of the new B-spline curve.
4) Compare BBox2 against BBox1. If BBox2 is pretty much the same size as BBox1, we are done. If BBox2 is considerably smaller than BBox1, repeat step 2 to 4 until convergence.

like image 29
fang Avatar answered Sep 18 '22 17:09

fang


Most of this is addressed in An algorithm to find bounding box of closed bezier curves? except here we have cubic Beziers and there they were dealing with quadratic Bezier curves.

Essentially you need to take the derivatives of each of the coordinate functions. If the x-coord is given by

x = A (1-t)^3 +3 B t (1-t)^2 + 3 C t^2 (1-t) + D t^3

differentiating with respect to t.

dx/dt =  3 (B - A) (1-t)^2 + 6 (C - B) (1-t) t + 3 (D - C) t^2
      =  [3 (D - C) - 6 (C - B) + 3 (B - A)] t^2
       + [ -6 (B - A) - 6 (C - B)] t
       + 3 (B - A) 
      =  (3 D - 9 C + 9 B - 3 A) t^2 + (6 A - 12 B + 6 C) t + 3 (B - A)

this is a quadratic which we can write at a t^2 + b t + c. We want to solve dx/dt = 0 which you can do using the quadratic formula

- b +/- sqrt(b^2-4 a c)
-----------------------
        2 a

Solving this will either gives two solutions t0, t1 say, no solutions or in rare case just one solution. We are only interest in solutions with 0 <= t <= 1. You will have a maximum of four candidate points, the two end points and the two solutions. Its a simple matter to find which of these give the extreme points.

You can repeat the same process for each coordinate and then get the bounding box.

I've put this for the 2D case in a js fiddle http://jsfiddle.net/SalixAlba/QQnvm/4/

like image 36
Salix alba Avatar answered Sep 17 '22 17:09

Salix alba