首页 文章

贝塞尔曲线评估

提问于
浏览
1

我在这里使用de Casteljau的算法http://www.cgafaq.info/wiki/B%C3%A9zier_curve_evaluation来关注本文,我尝试使用主题Drawing Bezier curves using De Casteljau Algorithm in C++ , OpenGL来帮助 . 没有成功 .

评估时,我的bezier曲线看起来像这样

正如你所看到的,即使它不能按照我想要的方式工作,所有的点确实在曲线上 . 我不认为这个算法因此而不准确 .

这是我在该图像顶部曲线上的点:(0,0)(2,0)(2,2)(4,2)第二条曲线使用相同的点集,除了第三点是(0, 2),即第一点上方的两个单位,形成更陡峭的曲线 .

出了点问题 . 我应该为 t 输入0.25,它应该为X值吐出1.0,而.75应该总是返回3.假设 t 是时间 . 它应该以恒定的速度发展,是吗?恰好25%的方式,X值应该是1.0,然后Y应该与该值相关联 .

有没有足够的方法来评估贝塞尔曲线?有谁知道这里发生了什么?

谢谢你的帮助! :)

EDIT------

我在Google搜索http://www.tsplines.com/resources/class_notes/Bezier_curves.pdf中找到了这本书,这是我在显式/非参数贝塞尔曲线上找到的页面 . 它们是多项式,表示为贝塞尔曲线,这就是我在这里要做的 . 这是书中的那个页面:

任何人都知道如何将贝塞尔曲线转换为参数曲线?我现在可以打开另一个帖子......

EDIT AGAIN AS OF 1 NOVEMBER 2011-------

我试图构建的是像Maya的动画图形编辑器,例如http://www.youtube.com/watch?v=tckN35eYJtg&t=240,其中用于修改曲线的贝塞尔控制点更像是相等长度的切线修改器 . 老实说,我不记得他们是等长的 . 通过强制使用这样的系统,您可以100%确保结果是一个函数并且不包含重叠的段 .

我找到了这个,可能有我的答案http://create.msdn.com/en-US/education/catalog/utility/curve_editor

5 回答

  • 0

    毕竟这一次,我一直在寻找hermite曲线 . 隐士是好的,因为在一个维度上他们保证产生可以评估为XY点的功能曲线 . 我和贝塞尔混淆了隐士 .

  • 11

    在这里,您可以看到在the nomenclature in your link之后在Mathematica中实现的算法,以及您的两个图:

    (*Function Definitions*)
    
    lerp[a_, b_, t_] := (1 - t) a + t b;
    pts1[t_] := {
       lerp[pts[[1]], pts[[2]], t],
       lerp[pts[[2]], pts[[3]], t],
       lerp[pts[[3]], pts[[4]], t]};
    pts2[t_] := {
       lerp[pts1[t][[1]], pts1[t][[2]], t],
       lerp[pts1[t][[2]], pts1[t][[3]], t]};
    pts3[t_] := {
       lerp[pts2[t][[1]], pts2[t][[2]], t]};
    
    (*Usages*)
    
    pts = {{0, 0}, {2, 0}, {2, 2}, {4, 2}};
    Framed@Show[ParametricPlot[pts3[t], {t, 0, 1}, Axes -> True], 
                Graphics[{Red, PointSize[Large], Point@pts}]]
    
    pts = {{0, 0}, {2, 0}, {0, 2}, {4, 2}};
    Framed@Show[ParametricPlot[pts3[t], {t, 0, 1}, Axes -> True], 
                Graphics[{Red, PointSize[Large], Point@pts}]]
    

    enter image description here

    顺便说一下,曲线由以下参数方程定义,它们是上面代码中的函数 pts3[t]

    c1[t_] := {2 t (3 + t (-3 + 2 t)), (* <- X component *)
                     2 (3 - 2 t) t^2}  (* <- Y component *)
    

    c2[t_] := {2 t (3 + t (-6 + 5 t)), (* <- X component *)
                   , 2 (3 - 2 t) t^2}  (* <- Y component *)
    

    尝试密谋他们!

    采用这些曲线方程中的任何一个,并通过求解三次多项式,在这些情况下,你可以得到y [x]的表达式,这当然不总是可行的 . 只是为了让你了解它,从你得到的第一条曲线(C语法):

    y[x]= 3 - x - 3/Power(-2 + x + Sqrt(5 + (-4 + x)*x),1/3) + 
                  3*Power(-2 + x + Sqrt(5 + (-4 + x)*x),1/3)
    

    Try plotting it!

    Edit

    只是一个娱乐:

    Mathematica是一种功能非常强大的函数式语言,事实上整个算法可以表示为一个单一的算法:

    f = Nest[(1 - t) #[[1]] + t #[[2]] & /@ Partition[#, 2, 1] &, #, Length@# - 1] &
    

    f@{{0, 0}, {2, 0}, {0, 2}, {4, 2}}
    

    给出了上述结果,但支持任意数量的点 .

    让我们尝试六个随机点:

    p = RandomReal[1, {6, 2}];
    Framed@Show[
      Graphics[{Red, PointSize[Large], Point@p}],
      ParametricPlot[f@p, {t, 0, 1}, Axes -> True]]
    

    enter image description here

    此外,相同的功能在3D中起作用:

    p = RandomReal[1, {4, 3}];
    Framed@Show[
      Graphics3D[{Red, PointSize[Large], Point@p}],
      ParametricPlot3D[f[p], {t, 0, 1}, Axes -> True]]
    

    enter image description here

  • 0

    “假设时间到了 . ”

    这是问题 - 不是时候 . 曲线具有自己的t变化率,具体取决于切线的大小 . 像Jason所说的那样,后续点之间的距离必须相同,t的顺序与时间相同 . 这正是Maya曲线编辑器中的非加权模式(默认情况下使用) . 所以对于如何解决这个问题,这是一个非常好的答案 . 要使其适用于任意切线,必须将时间转换为t . 您可以通过计算x(或时间)方向的贝塞尔方程来找到t .

    Px =(1-t)^ 3(P1x)3t(1-t)^ 2(P2x)3t ^ 2(1-t)(P3x)t ^ 3(P4x)

    Px是你的时间,所以你知道这里的一切,但是 . 你必须求解一个三次方程来找到根 . 找到你需要的确切根,有一个棘手的部分 . 然后你解决了另一个方程式来找到Py(你正在寻找的实际值),现在知道t:

    Py =(1-t)^ 3(P1y)3t(1-t)^ 2(P2y)3t ^ 2(1-t)(P3y)t ^ 3(P4y)

    这就是Maya中的加权曲线 . 我知道这个问题已经过时了,但是我整整一天都在研究这个简单的事情,没有人能够确切地解释会发生什么 . 否则,计算过程本身就写在很多地方,例如Maya API手册 . Maya devkit还有一个源代码来执行此操作 .

  • 9

    听起来你实际上只是想要一维立方贝塞尔曲线而不是你所拥有的二维曲线 . 具体来说,你真正想要的只是一个从0开始的三次多项式段,当在0到4的域上进行求值时,它会上升到2.所以你可以使用一些基本的数学并找到多项式:

    f(x) = a + b*x + c*x^2 + d*x^3
    f(0) = 0
    f(4) = 2
    

    这留下了两个自由度 .
    取该函数的导数:

    f'(x) = b + 2*c*x + 3*d*x^2
    

    如果你想让它在开始时陡峭,然后在结束时平稳,你可能会说:

    f'(0) = 10
    f'(4) = 0
    

    然后我们可以插入值 . ab 是免费的,因为我们的评估为零 .

    a = 0
    b = 10
    

    所以然后我们有:

    f(4) = 2 = 40 + c*16 + d*64
    f'(4) = 0 = 10 + c*8 + d*48
    

    这是一个非常容易解决的线性系统 . 为了完整起见,我们得到:

    16c + 64d = -38
     8c + 48d = -10
    

    所以-

    1/(16*48 - 8*64)|48 -64||-38| = |c| = |-37/8 |
                    |-8  16||-10|   |d|   |  9/16|
    
    f(x) = 10*x - (37/8)*x^2 + (9/16)*x^3
    

    相反,如果您决定要使用Bezier控制点,只需选择4个y值控制点并识别为了在[0,1]中得到 t ,您只需要说 t=x/4 (记住如果你还需要衍生品,你也必须在那里做一些改变) .


    添加:

    如果您碰巧知道要开始和结束的点和导数,但是您想使用Bezier控制点 P1P2P3P4 ,则映射就是这样(假设曲线参数化为0到1):

    P1 = f(0)
    P2 = f'(0)/3 + f(0)
    P3 = f(1) - f'(1)/3
    P4 = f(1)
    

    如果出于某种原因,您想要坚持使用2D Bezier控制点,并希望确保 x 维度从0到2线性提前,当 t 从0提高到1时,那么您可以使用控制点 (0,y1) (2/3,y2) (4/3,y3) (2,y4) 来实现 . 你可以看到我只是让 x 维度从0开始,结束于2,并且具有2的恒定斜率(导数)(相对于 t ) . 然后你只需要y坐标就可以了 . 不同的尺寸基本上彼此独立 .

  • 4

    贝塞尔曲线可以通过求解x,y和z坐标的以下参数方程来解决(如果它只是2D,只做x和y):

    Px = (1-t)^3(P1x) + 3t(1-t)^2(P2x) + 3t^2(1-t)(P3x) + t^3(P4x)
    Py = (1-t)^3(P1y) + 3t(1-t)^2(P2y) + 3t^2(1-t)(P3y) + t^3(P4y)
    Pz = (1-t)^3(P1z) + 3t(1-t)^2(P2z) + 3t^2(1-t)(P3z) + t^3(P4z)
    

    你也可以通过乘以矩阵方程ABC = X来解决这个问题,其中:

    • 矩阵A是1x4矩阵,表示 t 的幂的值

    • 矩阵B是 t 的幂的系数,是一个下三角形的4x4矩阵

    • 矩阵C是一个4x3矩阵,表示3D空间中的四个贝塞尔点中的每一个(它将是2D空间中的4x2矩阵)

    这将如下所示:

    matrix equation

    (更新 - 左下角1应为-1)

    方程的两种形式(参数和矩阵形式)的一个重要注意事项是 t 在[0,1]范围内 .

    而不是试图解决 t 的值,这将给出 xy 的整数值,这将是非常耗时的,因为你只需要在 t 值中创建足够小的差值就可以了得更好曲线上任意两点之间的值小于像素值增量 . 换句话说,两个点 P(t1)P(t2) 之间的距离使得它小于像素值 . 或者,您可以在 t 中使用较大的微分,并简单地在 P(t1)P(t2) 之间进行线性插值,请记住,如果 P(t1)P(t2) 之间的差值对于 t 的给定范围不够小,则曲线可能不是"smooth" ,1] .

    从视觉角度找到 t 中必要的微分以创建相当"smooth"曲线的好方法是实际测量定义贝塞尔曲线的四个点之间的距离 . 测量从P1到P2,P2到P3和P3到P4的距离 . 然后取最长距离,并使用该值的倒数作为 t 的差值 . 您可能仍需要在点之间进行一些线性插值,但每个"linear"子曲线中的像素数应该相当小,因此曲线本身看起来会相当平滑 . 您始终可以从此初始值减小 t 上的差值,使其成为"smoother" .

    最后,回答你的问题:

    假设是时间 . 它应该以恒定的速度发展,是吗?恰好25%的方式,X值应该是1.0,然后Y应该与该值相关联 .

    不,这是不正确的,原因是矢量(P2 - P1)和(P3 - P4)不仅与P1和P4的贝塞尔曲线相切,而且它们的长度定义了这些点沿曲线的速度同样 . 因此,如果向量(P2-P1)是一个短距离,那么这意味着在给定的时间内 t ,你将不会从点P1移动很远...这转换为沿着曲线的x,y值为给定的 t 固定差分非常紧密地打包在一起 . 当你向P1移动时,你的速度实际上是"slowing down" . 根据矢量的长度(P3-P4),在曲线上的P4处发生相同的效果 . 沿着曲线的速度的唯一方法是"constant",因此 t 的公共差分的任何点之间的距离都是相同的,如果所有三个部分的长度(P2-P1),则为(P3-P2) ),和(P4 - P3)是相同的 . 这表明沿曲线的速度没有变化 .

相关问题