繁体   English   中英

用贝塞尔曲线绘制圆弧

[英]Drawing arc with bezier curves

我正在尝试使用贝塞尔曲线绘制圆弧。 我了解到不能使用贝塞尔曲线绘制完美的圆,但是可以接近。 不幸的是,数学太复杂了,我个人无法弄清楚。

我可以将下面的A1切片创建为三角形,但无法弄清楚如何确定控制点。 另外,如果我尝试沿相反的方向从圆中绘制切片,请注意控制点似乎指向负方向。

因此,如果我想要一个半径为R的圆的切片并且已经计算出锚点,那么如何计算控制点1和控制点2的位置?

例

冯元在他的《 Windows图形编程》一书中提出了一种简单的方法:建立一个以OX轴为中心的半径为1的圆弧,为其计算Bezier近似值,并缩放,平移和旋转所需圆弧参数的控制点。 这是我针对大型弧修改的该方法的实现(在Delphi中)。 C ++源代码可以在Internet上找到,但是我希望逻辑清楚。

  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;

Duncan帖子引用的文章实际上是90度圆弧的结果,该结果来自Tor Dokken(主要作者)并于1990年在《计算机辅助几何设计》第7卷上发表。它列举了两种近似90度圆弧的方法。 :标准方法和更好的方法。 我将在下面列出“标准方法”的一般公式,并省略“更好方法”的一般公式,因为它需要大量输入:

对于具有角跨度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)*棕褐色(A / 4)

请注意,以这种方式获得的三次贝塞尔曲线近似值始终会插补圆弧的两个端点和中点,并且近似误差始终为正,这意味着三次贝塞尔曲线总是位于圆弧“外部”。

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

误差最大值=(4/27)*(power(sin(A / 4),6)/ power(cos(A / 4),2))

当您想要在一定的公差范围内近似一般的圆弧(任意角度范围和任何半径的半径)时,可以使用此公式计算将圆弧分成多少段并使用三次方贝塞尔曲线近似每个圆弧段曲线。 由于此三次贝塞尔曲线将遵循端点和结束斜率,因此所有获得的三次贝塞尔曲线将平滑地连接在一起。

本文给出了一组4个贝塞尔曲线,这些曲线生成非常接近的圆。 它将圆分成四个四分之一,每个曲线生成圆的1/4。

我不知道您怎么想出沿圆弧的任意弧的控制点。 您将使用Trig查找起点和终点,但中间点会更难。

文章结论:

通过这种近似,最大径向漂移为0.019608%。 这比标准近似值好28%。 这是最终结果:

图4.贝塞尔逼近与圆几乎无法区分。 使用贝塞尔曲线创建图4:P_0 =(0,1),P_1 =(c,1),P_2 =(1,c),P_3 =(1,0)P_0 =(1,0),P_1 = (1,-c),P_2 =(c,-1),P_3 =(0,-1)P_0 =(0,-1),P_1 =(-c,-1),P_3 =(-1,- 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的圆,则可以将Bezier曲线用于1/4圆,并通过将t参数的范围更改为一个范围来绘制该圆弧的一部分小于t = 0-> t = 1。 您需要对点应用旋转变换,以使其围绕圆移动。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM