用贝塞尔曲线绘制弧 [英] Drawing arc with bezier curves

查看:183
本文介绍了用贝塞尔曲线绘制弧的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图用贝塞尔曲线绘制弧线。我已经知道,你不能用贝塞尔曲线绘制完美的圆,但你可以靠近。不幸的是,数学过于复杂,我无法亲自理解它。



我可以将A1切片创建为三角形,但我无法弄清楚确定控制点。另外,如果我尝试在相反的方向上画一个圆圈,注意控制点似乎指向负方向。

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

解决方案

冯远在他的书 Windows图形编程中提出了简单的方法:建立一个半径为1的圆弧,以OX轴为中心,计算它的贝塞尔近似值,并为所需的弧参数缩放,平移和旋转控制点。这里是我实现这个方法(在Delphi中),修改为大弧。 C ++源代码可以在互联网的某个地方找到,但我希望逻辑清楚。

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

结果:

 键入
TPointArray = TPoint数组;

//计算贝塞尔控制点数组
//用于具有中心CX,CY和半径的圆弧R
过程GenerateBezierArc(CX,CY,R:Integer;
StartAngle,SweepAngle:Double;
var Pts:TPointArray);
//冯元书的C-Pascal翻译,纠正源错误
var
iCurve,NCurves:Integer;
我:整数;
x0,y0,tx,ty,sn,cs,ASweep,AStart:Double;
Px,Py:Double的数组[0 .. 3];
如果SweepAngle = 0,则开始
,然后
退出;
//如果SweepAngle太大,将弧线划分为更小的
NCurves:= Ceil(Abs(SweepAngle)/(Pi / 2));
SetLength(Pts,3 * NCurves + 1);
ASweep:= SweepAngle / NCurves;

//计算Bezier的控制点。圆弧半径为1,
//圆心位于(0,0),圆弧中间位于(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;

//控制点的旋转和平移
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));

用于iCurve:= 0用于NCurves - 1用于开始
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;


I am trying to draw an arc using bezier curves. I have learned that you can't draw a perfect circle using bezier curves but you can come close. Unfortunately the math is too complicated and I can't personally figure it out.

I can create the A1 slice below as a triangle, but I can't figure out how to determine the control points. Also if I try drawing a slice out of a circle in the opposite direction, notice how the control points seem to point in the negative direction.

So if I want a slice of a circle with a radius R and I have already computed the anchor points, how can I calculate the position of control point 1 and control point 2???

解决方案

Feng Yuan proposed simple method in his book Windows Graphics Programming: build an arc with radius 1, centered at OX axis, calculate Bezier approximation for it, and scale, translate and rotate control points for needed arc parameters. Here is my implementation of this method (in Delphi), modified for large arcs. C++ sources can be found somewhere in the Internet, but I hope that the logic is clear.

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

result:

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;

这篇关于用贝塞尔曲线绘制弧的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆