Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Math 在多个点拆分三次bezier曲线_Math_Curve_Bezier - Fatal编程技术网

Math 在多个点拆分三次bezier曲线

Math 在多个点拆分三次bezier曲线,math,curve,bezier,Math,Curve,Bezier,我正在写一个算法,将一条三次贝塞尔曲线分割成多条曲线(最多4条)。我从一开始就有我想要分割的每个点的t值。我还有一个算法,可以将曲线分割一次: SubdivPoints subdivideBezier(Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3, float t) { Vector2 p11 = (p1 - p0) * t + p0; Vector2 p21 = (p2 - p1) * t + p1; Vector2 p3

我正在写一个算法,将一条三次贝塞尔曲线分割成多条曲线(最多4条)。我从一开始就有我想要分割的每个点的t值。我还有一个算法,可以将曲线分割一次:

SubdivPoints subdivideBezier(Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3, float t)
{
    Vector2 p11 = (p1 - p0) * t + p0;
    Vector2 p21 = (p2 - p1) * t + p1;
    Vector2 p31 = (p3 - p2) * t + p2;

    Vector2 p12 = (p21 - p11) * t + p11;
    Vector2 p22 = (p31 - p21) * t + p21;

    Vector2 p13 = (p22 - p12) * t + p12;

    return SubdivPoints(p11, p12, p22, p31, p13);
}

我的问题是,有没有一种简单的方法可以将其扩展为多次拆分?我想在每次分割之后,我都想重新计算t值;我想知道的一件事是,简单的算术在这里是否有效。例如,假设t值为0.2和0.6。我在t=0.2时分割曲线,得到两条曲线。第二条曲线覆盖了原始曲线的t值0.2很难说,即使您当前的方法有效,因为我们看不到
子节点后面的内容。我可以想出两种方法:

  • 代数的

    如果你把你的问题看作是多项式的参数
    t
    缩放,那么它就变得更清晰了。例如,您需要零件t=
    的控制点。这意味着我们需要形成新的控制点,用参数
    u=
    表示相同的曲线。怎么做

  • 将BEZIER写成多项式
  • 每个轴都可以以相同的方式单独完成。s让我们只关注
    x
    -轴。我们有4个贝塞尔控制点,x坐标
    (x0,x1,x2,x3)
    。如果我们应用bernstein多项式形成三次多项式,我们得到:

    x(t)=      (                           (    x0))
        +    t*(                  (3.0*x1)-(3.0*x0))
        +  t*t*(         (3.0*x2)-(6.0*x1)+(3.0*x0))
        +t*t*t*((    x3)-(3.0*x2)+(3.0*x1)-(    x0))
    
  • 通过替换重新缩放参数
  • 为此使用线性插值,以便:

    t0=0.25 -> u0=0.0
    t1=0.50 -> u1=1.0
    t=t0+(t1-t0)*(u-u0)/(u1-u0)
    t=0.25+0.5*u
    
    现在用
    u
    而不是t重写多项式

    x(t)=             (                           (    x0))
        +(0.25+u/2)  *(                  (3.0*x1)-(3.0*x0))
        +(0.25+u/2)^2*(         (3.0*x2)-(6.0*x1)+(3.0*x0))
        +(0.25+u/2)^3*((    x3)-(3.0*x2)+(3.0*x1)-(    x0))
    
  • 更改多项式形式以再次匹配贝塞尔方程
  • 现在您需要为
    u^0、u^1、u^2、u^3
    分离多项式项,并对每个项进行改革以匹配贝塞尔风格(来自#1)。从中提取新的控制点

    例如,术语u^3是这样的。获得u^3的唯一可能性是从

    (1/4+u/2)^3= (1/8)*u^3 + (3/16)*u^2 + (3/32)*u + (1/64)
    
    因此,分隔的
    u^3
    术语将为:

    u*u*u*((    x3)-(3.0*x2)+(3.0*x1)-(    x0))/8
    
    其他的会有点复杂,因为你需要把所有的线组合在一起。。。简化后,需要分离新坐标。正如你所看到的,这有点疯狂,但也有代数解算器,比如为Windows导出

    很抱歉,我没有时间/心情/胃口对所有术语进行完整的示例,但你会看到这将是一个相当疯狂的过程

  • 曲线拟合

    这是基于您正在查找控制点的坐标并检查它与所需曲线的距离。所以尽可能地测试“”“点并记住目标范围上的原始曲线和新曲线之间的紧密匹配。这是无法解决的,因为可能有无限多的控制点,所以我们需要通过开发一些东西将这些控制点缩减到可管理的规模。例如,我们现在的控制点将不会远离原始控制点,因此我们可以使用它来限制每个点的面积。您可以使用这个或任何其他最小化技术

    如果使用插值立方,也可以获得更好的起点。看见因此:

  • 从贝塞尔曲线计算4个新的插值立方控制点

    所以如果我们的范围和以前一样的话

    X0 = BEZIER(t0-(t1-t0))
    X1 = BEZIER(t0)
    X2 = BEZIER(t1)
    X3 = BEZIER(t1+(t1-t0))
    
    这些是插值立方控制点,而不是贝塞尔。它们应该均匀分布
    X1,X2
    是曲线端点,
    X0,X3
    在它们之前和之后,以尽可能保持局部形状和参数的线性

  • (X0,X1,X2,X3)
    转换回贝塞尔控制点
    (X0,X1,X2,X3)

    您可以使用上面链接中的我的公式:

    // input: X0,Y0,..X3,Y3  ... interpolation control points
    // output: x0,y0,..x3,y3 ... Bezier control points
        double x0,y0,x1,y1,x2,y2,x3,y3,m=1.0/9.0;
        x0=X1;             y0=Y1;
        x1=X1+((X1-X0)*m); y1=Y1+((Y1-Y0)*m);
        x2=X2+((X2-X3)*m); y2=Y2+((Y2-Y3)*m);
        x3=X2;             y3=Y2;
    
    正如您所见,每个轴的计算方式相同

  • 对BEZIER控制点应用近似搜索

    新的
    (x0,x1,x2,x3)
    还不精确,因为盲目地改变控制点,我们可能会错过一些曲线扭曲形状的局部极值。所以我们需要寻找真正的。幸运的是,新的控制点
    (x0',x1',x2',x3')
    将非常接近这些点,因此现在我们必须搜索每个点,仅在其相对部分附近,周围有一些合理的半径(如边界框
    大小/8
    或其他什么…,您将看到结果并可以调整

  • [notes]

    如果您需要精确的结果,则只有#1方法可用。方法#2总是会有一些错误。如果形状不需要精确,有时将插值立方转换为BEZIER而无需最终拟合就足够了(如果切割区域内/附近的形状不太复杂)

    正如我之前所写的,如果不知道您的
    子节点使用了哪种原则,就不可能回答重复使用它会产生什么结果


    此外,您没有指定解决方案的约束,如结果的准确性、速度/运行时限制……如果范围是固定的(恒定的)或在运行期间可能会发生变化(这将使#1方法非常复杂,因为您需要将范围作为变量处理到最后)

    ,因为您的subdivideBezier()函数确实遵循了De Casteljau算法,我假设它可以在参数t处细分一条三次Bezier曲线。所以,是的,继续在不同的参数下细分(比如t2),您所需要做的就是找出细分后的曲线t2,根据该曲线计算新的t2*并细分。在您希望在t=0.2和0.6处细分的示例中,0.6的新参数应为(0.6-0.2)/(1-0.2)=0.5。所以,你可以简单地在t=0.5处细分第二条曲线。

    这就是我希望我能做的,但是这在数学上被证明了吗?我的意思是,我可以这样做,看看我能不能