Tho*_*lik 1 c++ algorithm math geometry bezier
我在这里使用de Casteljau的算法http://www.cgafaq.info/wiki/B%C3%A9zier_curve_evaluation来关注本文,我尝试使用在C++,OpenGL中使用De Casteljau算法绘制Bezier曲线的主题来提供帮助.没有成功.
评估时,我的bezier曲线看起来像这样
正如你所看到的,即使它不起作用我想要它,所有的点确实在曲线上.由于这个原因,我不认为这个算法是不准确的.
这是我在该图像顶部曲线上的点:(0,0)(2,0)(2,2)(4,2)第二条曲线使用相同的点集,除了第三点是(0, 2),即第一点上方的两个单元,形成更陡的曲线.
出了点问题.我应该输入0.25 for t
,它应该吐出1.0的X值,而.75应该总是返回3.假设t
是时间.它应该以恒定的速度发展,是吗?恰好25%的方式,X值应该是1.0,然后Y应该与该值相关联.
有没有足够的方法来评估贝塞尔曲线?有谁知道这里发生了什么?
谢谢你的帮助!:)
编辑 - - -
我在谷歌搜索http://www.tsplines.com/resources/class_notes/Bezier_curves.pdf中找到了这本书,这是我在显式/非参数贝塞尔曲线上找到的页面.它们是多项式,表示为贝塞尔曲线,这就是我在这里要做的.这是本书的那一页:
任何人都知道如何将贝塞尔曲线转换为参数曲线?我现在可以开一个不同的主题......
自2011年11月1日起编辑-------
我意识到我只是问了一半的问题,就像我应该的那样清楚.我正在尝试构建的是Maya的动画图形编辑器,例如http://www.youtube.com/watch?v=tckN35eYJtg&t=240,其中用于修改曲线的贝塞尔控制点更像是切线修改器长度相等.老实说,我不记得他们是等长的.通过强制使用这样的系统,您可以100%确保结果是一个函数并且不包含重叠的段.
我找到了这个,可能有我的答案http://create.msdn.com/en-US/education/catalog/utility/curve_editor
Dr.*_*ius 12
在这里,您可以看到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}]]
Run Code Online (Sandbox Code Playgroud)
顺便说一句,曲线由以下参数方程定义,它们是pts3[t]
上面代码中的函数:
c1[t_] := {2 t (3 + t (-3 + 2 t)), (* <- X component *)
2 (3 - 2 t) t^2} (* <- Y component *)
Run Code Online (Sandbox Code Playgroud)
和
c2[t_] := {2 t (3 + t (-6 + 5 t)), (* <- X component *)
, 2 (3 - 2 t) t^2} (* <- Y component *)
Run Code Online (Sandbox Code Playgroud)
尝试密谋他们!
采用这些曲线方程中的任何一个,并通过求解三次多项式,在这些情况下,您可以得到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)
Run Code Online (Sandbox Code Playgroud)
编辑
只是一个娱乐:
数学是一个相当强大的功能性语言,而事实上整个算法可以表示为一个班轮:
f = Nest[(1 - t) #[[1]] + t #[[2]] & /@ Partition[#, 2, 1] &, #, Length@# - 1] &
Run Code Online (Sandbox Code Playgroud)
如
f@{{0, 0}, {2, 0}, {0, 2}, {4, 2}}
Run Code Online (Sandbox Code Playgroud)
给出了上述结果,但支持任意数量的点.
让我们尝试六个随机点:
p = RandomReal[1, {6, 2}];
Framed@Show[
Graphics[{Red, PointSize[Large], Point@p}],
ParametricPlot[f@p, {t, 0, 1}, Axes -> True]]
Run Code Online (Sandbox Code Playgroud)
而且,相同的功能在3D中起作用:
p = RandomReal[1, {4, 3}];
Framed@Show[
Graphics3D[{Red, PointSize[Large], Point@p}],
ParametricPlot3D[f[p], {t, 0, 1}, Axes -> True]]
Run Code Online (Sandbox Code Playgroud)
贝塞尔曲线可以通过求解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)
Run Code Online (Sandbox Code Playgroud)
你也可以通过乘以矩阵方程ABC = X来解决这个问题,其中:
t
t
,并且是下三角形4×4矩阵这将如下所示:
(更新 - 左下角1应为-1)
方程的两种形式(参数和矩阵形式)中的重要注释t
是在[0,1]范围内.
而不是试图解决这个值t
将给你积分值x
和y
,这将是耗时的,因为你基本上解决了三次多项式的实根,所以简单地创建一个更好t
值的足够小,使得曲线上任意两点之间的差异小于像素值增量.换句话说,两个点之间的距离P(t1)
和P(t2)
使得其小于像素值.可替换地,可以使用在一个较大的差t
,并简单地之间线性内插P(t1)
和P(t2)
,牢记的是,曲线可能不"平滑"如果之间的差P(t1)
和P(t2)
不足够小的给定范围内t
从[0,1].
t
从视觉角度找到创建相当"平滑"曲线所需的微分的好方法是实际测量定义贝塞尔曲线的四个点之间的距离.测量从P1到P2,P2到P3和P3到P4的距离.然后取最长距离,并使用该值的倒数作为差值t
.您可能仍需要在点之间进行一些线性插值,但每个"线性"子曲线中的像素数应该相当小,因此曲线本身看起来相当平滑.您始终可以t
从此初始值减小差值,使其"更平滑".
最后,回答你的问题:
假设是时间.它应该以恒定的速度发展,是吗?恰好25%的方式,X值应该是1.0,然后Y应该与该值相关联.
不,这是不正确的,原因是矢量(P2 - P1)和(P3 - P4)不仅与P1和P4的贝塞尔曲线相切,而且它们的长度定义了这些点沿曲线的速度同样.因此,如果向量(P2-P1)是一个短距离,那么这意味着在给定的时间内t
,您将不会从P1点移动很远...这将转换为沿着曲线被包装的x,y值对于给定的固定微分,非常接近t
.当你向P1移动时,你有效地"减速"速度.根据矢量的长度(P3-P4),在曲线上的P4处发生相同的效果.沿着曲线的速度是"常数"的唯一方法,因此t
,如果所有三个部分的长度(P2-P1),(P3-),则公共差分的任何点之间的距离将是相同的. P2)和(P4-P3)是相同的.这表明沿曲线的速度没有变化.