Calculating the bounding box of cubic bezier curve

后端 未结 3 874
佛祖请我去吃肉
佛祖请我去吃肉 2020-12-31 16:09

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 o

相关标签:
3条回答
  • 2020-12-31 16:34

    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.

    0 讨论(0)
  • 2020-12-31 16:43

    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/

    0 讨论(0)
  • 2020-12-31 16:48

    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)}
        };
    }
    
    0 讨论(0)
提交回复
热议问题