C++ 为什么立方贝塞尔函数与windows api PolyBezier相比不精确?
我一直在寻找一种使用自定义函数绘制曲线/三次贝塞尔曲线的方法。然而,在互联网上找到的所有例子和类似的例子,彼此之间有点不同,通常会产生不同的结果,为什么。我尝试过的所有产品都不能产生与windows api PolyBezier相同的结果,这正是我所需要的 这是我当前绘制三次贝塞尔曲线的代码:C++ 为什么立方贝塞尔函数与windows api PolyBezier相比不精确?,c++,graphics,bezier,C++,Graphics,Bezier,我一直在寻找一种使用自定义函数绘制曲线/三次贝塞尔曲线的方法。然而,在互联网上找到的所有例子和类似的例子,彼此之间有点不同,通常会产生不同的结果,为什么。我尝试过的所有产品都不能产生与windows api PolyBezier相同的结果,这正是我所需要的 这是我当前绘制三次贝塞尔曲线的代码: double Factorial(int number) { double factorial = 1; if (number > 1) { for (in
double Factorial(int number)
{
double factorial = 1;
if (number > 1)
{
for (int count = 1; count <= number; count++) factorial = factorial * count;
}
return factorial;
}
double choose(double a, double b)
{
return Factorial(a) / (Factorial(b) * Factorial(a - b));
}
VOID MyPolyBezier(HDC hdc, PPOINT Pts, int Total)
{
float x, y;
MoveToEx(hdc, Pts[0].x, Pts[0].y, 0);
Total -= 1;
//for (float t = 0; t <= 1; t += (1./128.))
for (float t = 0; t <= 1; t += 0.0078125)
{
x = 0;
y = 0;
for (int I = 0; I <= Total; I++)
{
x += Pts[I].x * choose(Total, I) * pow(1 - t, Total - I) * pow(t, I);
y += Pts[I].y * choose(Total, I) * pow(1 - t, Total - I) * pow(t, I);
}
LineTo(hdc, x, y);
}
}
并附上我的坏结果的图片:
注:底部贝塞尔线为windowsPolyBezier版本
编辑:
最后一个目标,左边的窗口VS自定义功能。希望这在某种程度上有所帮助。
所以三次贝塞尔曲线是一条数学曲线。三次贝塞尔曲线是更一般曲线的一种特殊情况 三次贝塞尔曲线由4个控制点定义——一个起点和终点,以及2个控制点。通常,贝塞尔曲线按顺序有n个控制点 当时间参数t从0变为1时,绘制该线 要找出在时间t时n阶的一般贝塞尔函数的位置,请执行以下操作: 对于bezier中的每一对相邻控制点,找到它们的加权平均值,由t控制。因此,对于b之前的控制点a,在+b1-t处 使用这些n-1点形成n-1阶贝塞尔曲线 在时间t求解新的贝塞尔 当你碰到1度贝塞尔,停止。这就是你的观点
尝试编写一个基于贝塞尔曲线真实定义的算法,看看它与windows曲线的区别。这可能比采用某种近似值并协调两组错误更令人沮丧。Beziers无法直接绘制,因为公式适用于与x或y不直接相关的变量t。它是近似的,不同的算法会产生不同的近似值,更不用说舍入效果了。你可以将直线细分为128段,并在它们之间线性绘制。因此,在这128点上,你应该是好的-线是噪声-你的答案在节点之间是错误的。检查这128个点,看看它们是否在windows行上:如果不在,则表示windows使用的不是您的意思。半像素,不同的近似值,四舍五入-谁知道呢。这并不容易。顺便说一句,你的意思是精确。在找到实际的贝塞尔曲线并演示其渲染方式之前,以上内容不包含任何准确性证据。只是两个不同的近似值。我需要的精度与windows PolyBezier相同。我正在加载原始TrueType字体数据,并使用此处找到的windows方法将线条转换为立方贝塞尔:函数AppendPolyLineObezier和AppendQuadBsLineToBezier正在进行转换,我正在查看它们,如果我发现了什么,我将发布。对,因此步骤1:实现绘图以使用真实函数,不要选择和pow,然后查看您的代码是否生成相同的曲率。应该是这样的,因为只有一种方法可以计算贝塞尔曲线,好的,两种。这是一个对称函数,所以作为一个完整的图,你可以从t或1-t开始,结果是一样的。然后,如果它看起来太直线分段,开始增加你的t间隔精度,比如说0.001而不是0.007。最后:四舍五入问题。不要计算你在整数区域的坐标。计算浮点,然后在仅绘制时取整。
POINT TestPts[4];
BYTE TestType[4] = {PT_MOVETO, PT_BEZIERTO, PT_BEZIERTO, PT_BEZIERTO};
//set x, y points for the curved line.
TestPts[0].x = 50;
TestPts[0].y = 200;
TestPts[1].x = 100;
TestPts[1].y = 100;
TestPts[2].x = 150;
TestPts[2].y = 200;
TestPts[3].x = 200;
TestPts[3].y = 200;
//Draw using custom function.
MyPolyBezier(hdc, TestPts, 4);
//Move the curve down some.
TestPts[0].y += 10;
TestPts[1].y += 10;
TestPts[2].y += 10;
TestPts[3].y += 10;
//Draw using windows api.
//PolyDraw(hdc, TestPts, TestType, 4); //PolyDraw gives the same result as PolyBezier.
PolyBezier(hdc, TestPts, 4);