用贝塞尔曲线绘制弧

我正在尝试使用贝塞尔曲线绘制弧线。 我已经知道,你不能用贝塞尔曲线画一个完美的圆,但你可以靠近。 不幸的是,math太复杂了,我不能亲自搞清楚。

我可以创build一个三angular形下面的A1切片,但我不知道如何确定控制点。 另外,如果我尝试在相反的方向上画出一个圆圈,注意控制点似乎指向负方向。

所以,如果我想要一个半径为R的圆的切片,并且已经计算了定位点,那我怎样才能计算出控制点1和控制点2的位置?

例

冯远在他的书“ Windowsgraphics程序devise”中提出了简单的方法:以OX轴为中心build立一个半径为1的圆弧,计算其贝塞尔近似值,并对需要的圆弧参数进行缩放,平移和旋转控制点。 这里是我实现这个方法(在Delphi中),修改为大弧。 C ++源可以在互联网的某个地方find,但是我希望逻辑清晰。

  GenerateBezierArc(200, 200, 150, Pi / 4, 3 * Pi / 2, Pts); Canvas.PolyBezier(Pts); 

结果:

在这里输入图像说明

 type TPointArray = array of TPoint; //calculates array of Bezier control points //for circle arc with center CX, CY and radius R procedure GenerateBezierArc(CX, CY, R: Integer; StartAngle, SweepAngle: Double; var Pts: TPointArray); // C-Pascal translation from Feng Yuan book, with correction of source errors var iCurve, NCurves: Integer; i: Integer; x0, y0, tx, ty, sn, cs, ASweep, AStart: Double; Px, Py: array [0 .. 3] of Double; begin if SweepAngle = 0 then Exit; // if SweepAngle is too large, divide arc to smaller ones NCurves := Ceil(Abs(SweepAngle) / (Pi/2)); SetLength(Pts, 3 * NCurves + 1); ASweep := SweepAngle / NCurves; // calculates control points for Bezier approx. of arc with radius=1, // circle center at (0,0), middle of arc at (1,0) y0 := Sin(ASweep / 2); x0 := Cos(ASweep / 2); tx := (1 - x0) * 4 / 3; ty := y0 - tx * x0 / (y0 + 0.0001); Px[0] := x0; Py[0] := -y0; Px[1] := x0 + tx; Py[1] := -ty; Px[2] := x0 + tx; Py[2] := ty; Px[3] := x0; Py[3] := y0; // rotation and translation of control points sn := Sin(StartAngle + ASweep / 2); cs := Cos(StartAngle + ASweep / 2); Pts[0].X := CX + Round(R * (Px[0] * cs - Py[0] * sn)); Pts[0].Y := CY + Round(R * (Px[0] * sn + Py[0] * cs)); for iCurve := 0 to NCurves - 1 do begin AStart := StartAngle + ASweep * iCurve; sn := Sin(AStart + ASweep / 2); cs := Cos(AStart + ASweep / 2); for i := 1 to 3 do begin Pts[i + iCurve * 3].X := CX + Round(R * (Px[i] * cs - Py[i] * sn)); Pts[i + iCurve * 3].Y := CY + Round(R * (Px[i] * sn + Py[i] * cs)); end; end; end; 

这篇文章给出了一组4个贝塞尔曲线,它们产生了一个非常接近的圆。 它将圆圈分成四个四分之一,每条曲线产生四分之一的圆圈。

我不知道你是怎么想出沿着一个圆的任意弧的控制点。 你会用trig来find开始点和结束点,但是中间点会更难。

文章的结论是:

这个近似值的最大径向漂移为0.019608%。 这比标准近似值好28%。 这是最后的结果:

图4.贝塞尔近似与圆圈几乎没有区别。 图4是用Bézier曲线创build的:P_0 =(0,1),P_1 =(c,1),P_2 =(1,c),P_3 =(1,0)P_0 = (1,-c),P_2 =(c,-1),P_3 =(0,-1)P_0 =(0,-1),P_1 =(-c,-1),P_3 = c),P_4 =(-1,0)P_0 =(-1,0),P_1 =(-1,c),P_2 =(-c,1),P_3 =(0,1),其中c = 0.551915024494。

这是一个单位圆(半径为1的原点上的圆)您需要为其他半径值进行缩放。

编辑:

如果你认为你的弧线总是1/4或更小,那么你可以使用贝塞尔曲线1/4圈,并通过改变t参数的范围来画一部分弧线小于t = 0 – > t = 1。 你需要对你的点进行旋转变换来将它们移到圆上。

Duncan的文章引用的文章实际上是由Tor Dokken(主要作者)撰写的1990年出版的“计算机辅助几何devise”(Computer Aided Geometric Design Vol 7)期刊论文的90度圆弧的结果。它引用了两种近似90度弧的方法:一个标准的方法和一个更好的方法。 我将在下面列出“标准方法”的通用公式,并省略“更好的方法”的通用公式,因为它需要大量的input:

对于具有angular度跨度A和单位半径的圆弧,描述为C(t)=(cos(t),sin(t)),其中t = [0,A],可以获得良好的三次贝塞尔曲线近似以下控制点:

P(0)=(1,0),
P(1)=(1,0)+ L(0,1),
P(2)=(cosA,sinA)-L(-sinA,cosA),
P(3)=(cosA,sinA)

其中L是一个依赖于A的标量常数

L =(4/3)* tan(A / 4)

请注意,以这种方式获得的三次贝塞尔曲线近似总是内插圆弧的两个端点和中点,并且逼近误差总是正的,这意味着三次贝塞尔曲线总是在圆弧的“外侧”。

这个简单公式的最大径向误差(x(t)^ 2 + y(t)^ 2 – 1)是

Error_max =(4/27)*(power(sin(A / 4),6)/ power(cos(A / 4),2))

如果要在一定公差范围内逼近一般的圆弧(任何angular度范围和任何半径半径),可以使用此公式来计算需要将圆弧分割成多less个段,并使用三次贝塞尔曲线近似每个圆弧段曲线。 由于这个三次贝塞尔曲线将会遵循终点和终点斜率,所有获得的三次贝塞尔曲线将会平滑地连接在一起。