Math 三次bezier曲线边界盒的计算

Math 三次bezier曲线边界盒的计算,math,3d,curve,bezier,Math,3d,Curve,Bezier,我试图找到一个算法来计算一个给定的三次贝塞尔曲线的边界框。曲线位于三维空间中 除了曲线上的采样点和计算这些点的边界框之外,有没有数学方法可以做到这一点?除了这里我们有三次贝塞尔曲线,那里他们处理的是二次贝塞尔曲线之外,大部分都是在中讨论的 基本上你需要得到每个坐标函数的导数。如果x坐标由 x = A (1-t)^3 +3 B t (1-t)^2 + 3 C t^2 (1-t) + D t^3 关于t的区别 dx/dt = 3 (B - A) (1-t)^2 + 6 (C - B) (1-t)

我试图找到一个算法来计算一个给定的三次贝塞尔曲线的边界框。曲线位于三维空间中


除了曲线上的采样点和计算这些点的边界框之外,有没有数学方法可以做到这一点?

除了这里我们有三次贝塞尔曲线,那里他们处理的是二次贝塞尔曲线之外,大部分都是在中讨论的

基本上你需要得到每个坐标函数的导数。如果x坐标由

x = A (1-t)^3 +3 B t (1-t)^2 + 3 C t^2 (1-t) + D t^3
关于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)
这是一个二次曲线,我们可以在
at2+bt+c
处编写。我们想要求解dx/dt=0,你可以用二次公式来求解

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

解决这个问题要么给出两个解t0,t1,比如说,没有解,要么在极少数情况下只有一个解。我们只对0的解感兴趣,寻找三次Bezier曲线(甚至是任意阶B样条曲线)的边界框通常是通过找到曲线控制多边形的边界框来完成的。由于曲线始终以其控制多边形为边界,因此通过控制多边形获得的边界框保证包围曲线。还可以对曲线执行节点插入,并使控制多边形更接近曲线本身。因此,一般算法如下所示:

1) 从当前B样条曲线的控制多边形中查找其边界框(表示为BBox1)
2) 在B样条曲线中每个Bezier段的中间参数处插入结。
3) 找到新B样条曲线的边界框(表示为BBox2)。

4) 比较BBox2和BBox1。如果BBox2的大小与BBox1几乎相同,那么我们就完成了。如果BBox2比BBox1小得多,重复步骤2到步骤4直到收敛。

本文解释了细节,还提供了一个html5演示:

我在Snap.svg中找到了一个javascript来计算:
请参见bezierBBox和curveDim函数

我重写了一个javascript函数

//(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)}
    };
}
/(x0,y0)为起点;(x1,y1),(x2,y2)为控制点;(x3,y3)是终点。
函数bezierMinMax(x0,y0,x1,y1,x2,y2,x3,y3){
var tvalues=[]、xvalues=[]、yvalues=[]、,
a、 b、c、t、t1、t2、b2ac、sqrtb2ac;
对于(变量i=0;i<2;++i){
如果(i==0){
b=6*x0-12*x1+6*x2;
a=-3*x0+9*x1-9*x2+3*x3;
c=3*x1-3*x0;
}否则{
b=6*y0-12*y1+6*y2;
a=-3*y0+9*y1-9*y2+3*y3;
c=3*y1-3*y0;
}
if(数学abs(a)<1e-12){
if(数学abs(b)<1e-12){
继续;
}
t=-c/b;
if(0
这是更好的答案。具体来说,三次贝塞尔曲线(或任何贝塞尔曲线)完全由其控制点定义的凸包包围。太棒了,谢谢!我注意到了一种不稳定性,当
a==0
时,它给出了不正确的界限,因为
t1
t2
都是无穷大的。我用一个似乎有效的破解方法修复了它:
if(a==0)a=0.0000001一个例子:(实际上是一个二次曲线。)不过,这种攻击是毫无意义的。你不必使用黑客,只需检查如何处理这种情况的公式即可。如果a==0,你可以简单地求解方程
bt+c=0
,它给出了
t=-c/b
。嘿,二次曲线有这个版本吗?你可以很容易地将二次贝塞尔曲线转换成三次曲线。二次型的代码要短得多。非常感谢!工作完美,节省了我几个小时的搜索时间我也在用这个来表示二次型,但在某些情况下并不准确(比如控制点远离起点/终点)。我的错,我认为我错误地将二次型转换为三次型:/