用贝塞尔曲线绘制弧形

时间:2014-11-05 18:21:56

标签: ios objective-c swift geometry bezier

我正在尝试使用贝塞尔曲线绘制弧线。我已经知道你不能使用贝塞尔曲线绘制一个完美的圆,但你可以接近。不幸的是,数学太复杂了,我无法亲自弄明白。

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

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

Example

3 个答案:

答案 0 :(得分:1)

冯元在他的书Windows Graphics Programming中提出了简单的方法:建立一个半径为1的弧,以OX轴为中心,计算它的Bezier近似值,并对所需的弧参数进行缩放,平移和旋转控制点。这是我对此方法的实现(在Delphi中),针对大弧进行了修改。可以在Internet的某个地方找到C ++源代码,但我希望逻辑清晰。

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

结果:

enter image description here

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;

答案 1 :(得分:1)

Duncan的帖子引用的文章实际上是由Tor Dokken(主要作者)撰写并于1990年出版于计算机辅助几何设计第7卷的期刊论文的90度圆弧的结果。近似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)* tan(A / 4)

请注意,以这种方式获得的三次贝塞尔曲线近似总是插入圆弧的两个端点和中点,并且近似误差始终为正,这意味着三次贝塞尔曲线始终是"外部& #34;圆弧。

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

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

如果要在一定公差范围内逼近一般圆弧(任意角度范围和任意半径半径),可以使用此公式计算将圆弧打入并使用每个弧段近似所需的段数三次贝塞尔曲线。由于这个三次贝塞尔曲线将支持终点和终点斜率,所以获得的所有三次贝塞尔曲线将平滑地连接在一起。

答案 2 :(得分:0)

This article给出一组4条贝塞尔曲线,它们生成一个非常接近的圆的近似值。它将圆分为4个四分之一,每条曲线生成圆的1/4。

我不知道你是如何想出沿着圆圈的任意弧的控制点。您将使用trig来查找起点和终点,但中间点会更难。

文章的结论:

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

图4.Bézier近似几乎与圆形无法区分。 图4是使用Bézier曲线创建的: 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或更小的圆,那么您可以使用贝塞尔曲线1/4圈,并通过改变t参数的范围绘制该弧的一部分到小于t = 0的范围 - > T = 1。您需要对点进行旋转变换,以便围绕圆圈移动它们。